diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/osgi/OSGIResource.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/osgi/OSGIResource.java index 62e8c54a80b0..a308d7d5de3c 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/osgi/OSGIResource.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/osgi/OSGIResource.java @@ -544,7 +544,7 @@ private void removeReferences() { Logger.info( this, "Portlets Removed: " + OSGIUtil.getInstance().portletIDsStopped.toString()); //Remove Actionlets in the list - OSGIUtil.getInstance().actionletsStopped.forEach(p -> OSGIUtil.getInstance().workflowOsgiService.removeActionlet(p)); + OSGIUtil.getInstance().actionletsStopped.forEach(p -> OSGIUtil.getInstance().getWorkflowOsgiService().removeActionlet(p)); Logger.info( this, "Actionlets Removed: " + OSGIUtil.getInstance().actionletsStopped.toString()); //Cleanup lists diff --git a/dotCMS/src/main/java/com/dotmarketing/osgi/GenericBundleActivator.java b/dotCMS/src/main/java/com/dotmarketing/osgi/GenericBundleActivator.java index 597d4c78cafa..27e539168f1c 100644 --- a/dotCMS/src/main/java/com/dotmarketing/osgi/GenericBundleActivator.java +++ b/dotCMS/src/main/java/com/dotmarketing/osgi/GenericBundleActivator.java @@ -82,7 +82,6 @@ public abstract class GenericBundleActivator implements BundleActivator { private static final String MANIFEST_HEADER_OVERRIDE_CLASSES = "Override-Classes"; - private static final String INIT_PARAM_VIEW_JSP = "view-jsp"; private static final String INIT_PARAM_VIEW_TEMPLATE = "view-template"; public static final String BYTEBUDDY_CLASS_RELOADING_STRATEGY_NOT_SET_JAVA_AGENT_NOT_SET = "bytebuddy ClassReloadingStrategy not set [java agent not set?]"; @@ -90,8 +89,6 @@ public abstract class GenericBundleActivator implements BundleActivator { public static final String COM_LIFERAY_PORTLET_VELOCITY_PORTLET = "com.liferay.portlet.VelocityPortlet"; private BundleContext context; - - private PrimitiveToolboxManager toolboxManager; private CacheOSGIService cacheOSGIService; private ConditionletOSGIService conditionletOSGIService; @@ -109,7 +106,6 @@ public abstract class GenericBundleActivator implements BundleActivator { private final Collection postHooks = new ArrayList<>(); private final Collection overriddenClasses = new HashSet<>(); - protected ClassLoader getBundleClassloader () { return this.getClass().getClassLoader(); } @@ -563,21 +559,8 @@ protected void addRewriteRule ( String from, String to, String type, String name * @param context * @param actionlet */ - protected void registerActionlet ( BundleContext context, WorkFlowActionlet actionlet ) { - - //Getting the service to register our Actionlet - ServiceReference serviceRefSelected = context.getServiceReference( WorkflowAPIOsgiService.class.getName() ); - if ( serviceRefSelected == null ) { - return; - } - - - OSGIUtil.getInstance().workflowOsgiService = (WorkflowAPIOsgiService) context.getService( serviceRefSelected ); - OSGIUtil.getInstance().workflowOsgiService.addActionlet( actionlet.getClass() ); - actionlets.add( actionlet ); - - Logger.info( this, "Added actionlet: " + actionlet.getName() ); - OSGIUtil.getInstance().actionletsStopped.remove(actionlet.getClass().getCanonicalName()); + protected void registerActionlet(final BundleContext context, final WorkFlowActionlet actionlet) { + OSGIUtil.getInstance().registerActionlet(context, actionlet, actionlets); } /** @@ -831,7 +814,7 @@ protected void unpublishBundleServices () { */ protected void unregisterActionlets () { - if (OSGIUtil.getInstance().workflowOsgiService != null) { + if (OSGIUtil.getInstance().getWorkflowOsgiService() != null) { for ( WorkFlowActionlet actionlet : actionlets ) { if(!OSGIUtil.getInstance().actionletsStopped.contains(actionlet.getClass().getCanonicalName())){ OSGIUtil.getInstance().actionletsStopped.add(actionlet.getClass().getCanonicalName()); diff --git a/dotCMS/src/main/java/org/apache/felix/framework/OSGIUtil.java b/dotCMS/src/main/java/org/apache/felix/framework/OSGIUtil.java index c5fb629e973a..0c48ceb9c2e2 100644 --- a/dotCMS/src/main/java/org/apache/felix/framework/OSGIUtil.java +++ b/dotCMS/src/main/java/org/apache/felix/framework/OSGIUtil.java @@ -14,6 +14,7 @@ import com.dotmarketing.business.APILocator; import com.dotmarketing.exception.DotRuntimeException; import com.dotmarketing.osgi.HostActivator; +import com.dotmarketing.portlets.workflows.actionlet.WorkFlowActionlet; import com.dotmarketing.portlets.workflows.business.WorkflowAPIOsgiService; import com.dotmarketing.util.Config; import com.dotmarketing.util.DateUtil; @@ -23,7 +24,6 @@ import com.dotmarketing.util.UUIDGenerator; import com.dotmarketing.util.UtilMethods; import com.dotmarketing.util.WebKeys; -import com.google.common.collect.ImmutableList; import com.liferay.portal.language.LanguageUtil; import com.liferay.util.FileUtil; import com.liferay.util.MathUtil; @@ -83,17 +83,11 @@ */ public class OSGIUtil { + // by default the upload folder checker is 10 seconds + private static final int OSGI_CHECK_UPLOAD_FOLDER_FREQUENCY_DEFAULT_VAL = 10; private static final String OSGI_EXTRA_CONFIG_FILE_PATH_KEY = "OSGI_EXTRA_CONFIG_FILE_PATH_KEY"; private static final String OSGI_RESTART_LOCK_KEY = "osgi_restart_lock"; private static final String OSGI_CHECK_UPLOAD_FOLDER_FREQUENCY = "OSGI_CHECK_UPLOAD_FOLDER_FREQUENCY"; - // by default the upload folder checker is 10 seconds - private static final int OSGI_CHECK_UPLOAD_FOLDER_FREQUENCY_DEFAULT_VAL = 10; - - - //List of jar prefixes of the jars to be included in the osgi-extra.conf file - public final List portletIDsStopped = Collections.synchronizedList(new ArrayList<>()); - public final List actionletsStopped = Collections.synchronizedList(new ArrayList<>()); - public WorkflowAPIOsgiService workflowOsgiService; private static final String WEB_INF_FOLDER = "/WEB-INF"; private static final String FELIX_BASE_DIR = "felix.base.dir"; private static final String FELIX_UPLOAD_DIR = "felix.upload.dir"; @@ -101,17 +95,32 @@ public class OSGIUtil { private static final String FELIX_UNDEPLOYED_DIR = "felix.undeployed.dir"; private static final String FELIX_FRAMEWORK_STORAGE = org.osgi.framework.Constants.FRAMEWORK_STORAGE; private static final String AUTO_DEPLOY_DIR_PROPERTY = AutoProcessor.AUTO_DEPLOY_DIR_PROPERTY; + private static final String PROPERTY_OSGI_PACKAGES_EXTRA = "org.osgi.framework.system.packages.extra"; + // PUBSUB + private static final String TOPIC_NAME = OsgiRestartTopic.OSGI_RESTART_TOPIC; + /** + * Felix directory list + */ + private static final String[] FELIX_DIRECTORIES = new String[] { + FELIX_BASE_DIR, + FELIX_UPLOAD_DIR, + FELIX_FILEINSTALL_DIR, + FELIX_UNDEPLOYED_DIR, + AUTO_DEPLOY_DIR_PROPERTY, + FELIX_FRAMEWORK_STORAGE + }; + private static class OSGIUtilHolder { + private static final OSGIUtil instance = new OSGIUtil(); + } - private final Debouncer debouncer = new Debouncer(); + public static OSGIUtil getInstance() { + return OSGIUtilHolder.instance; + } + private final Debouncer debouncer = new Debouncer(); // PUBSUB - private final static String TOPIC_NAME = OsgiRestartTopic.OSGI_RESTART_TOPIC; private final DotPubSubProvider pubsub; - private final OsgiRestartTopic osgiRestartTopic; - - private Framework felixFramework; - //// When the strategy to discover jars on the upload folder is not by folder watcher (watchers do not work on docker) /// we have a job that runs every 10 seconds (it is configurable) and checks if there is any jars in the upload folder /// if they are; runs a process to reload (copy the jars to load folder and so on) @@ -121,45 +130,40 @@ public class OSGIUtil { // if some of the reads to the upload folder founds a jar, the counts are reset to the initial values again and the cycle begins one more time. private final AtomicInteger uploadFolderReadsCount = new AtomicInteger(0); private final AtomicInteger currentJobRestartIterationsCount = new AtomicInteger(0); - // Indicates the job were already started, so next restart of the OSGI framework won't create a new one job. private final AtomicBoolean isStartedOsgiRestartSchedule = new AtomicBoolean(false); - /** - * Felix directory list - */ - private static final String[] FELIX_DIRECTORIES = new String[] { - FELIX_BASE_DIR, FELIX_UPLOAD_DIR, FELIX_FILEINSTALL_DIR, FELIX_UNDEPLOYED_DIR, AUTO_DEPLOY_DIR_PROPERTY, FELIX_FRAMEWORK_STORAGE - }; - - public static final String BUNDLE_HTTP_BRIDGE_SYMBOLIC_NAME = "org.apache.felix.http.bundle"; - private static final String PROPERTY_OSGI_PACKAGES_EXTRA = "org.osgi.framework.system.packages.extra"; - public String FELIX_EXTRA_PACKAGES_FILE; - - public static OSGIUtil getInstance() { - return OSGIUtilHolder.instance; - } + private final long delay = Config.getLongProperty("OSGI_UPLOAD_DEBOUNCE_DELAY_MILLIS", 5000); + private final List> actionletsToRegister = + Collections.synchronizedList(new ArrayList<>()); + private final Object osgiLock = new Object(); + private Framework felixFramework; + private String felixExtraPackagesFile; + private WorkflowAPIOsgiService workflowOsgiService; + private Boolean osgiStarted = false; - private static class OSGIUtilHolder{ - private static OSGIUtil instance = new OSGIUtil(); - } + //List of jar prefixes of the jars to be included in the osgi-extra.conf file + public final List portletIDsStopped = Collections.synchronizedList(new ArrayList<>()); + public final List actionletsStopped = Collections.synchronizedList(new ArrayList<>()); private OSGIUtil() { - - - this.pubsub = DotPubSubProviderLocator.provider.get(); - this.osgiRestartTopic = new OsgiRestartTopic(); + this.pubsub = DotPubSubProviderLocator.provider.get(); + final OsgiRestartTopic osgiRestartTopic = new OsgiRestartTopic(); Logger.debug(this.getClass(), "Starting hook with PubSub on OSGI"); this.pubsub.start(); - this.pubsub.subscribe(this.osgiRestartTopic); + this.pubsub.subscribe(osgiRestartTopic); } - public List getPortletIDsStopped() { - return portletIDsStopped; + public WorkflowAPIOsgiService getWorkflowOsgiService() { + return workflowOsgiService; } - public List getActionletsStopped() { - return actionletsStopped; + public void setWorkflowOsgiService(final WorkflowAPIOsgiService workflowOsgiService) { + this.workflowOsgiService = workflowOsgiService; + } + + public List getPortletIDsStopped() { + return portletIDsStopped; } /** @@ -198,18 +202,14 @@ private Properties defaultProperties() { // Create host activator; HostActivator hostActivator = HostActivator.instance(); - felixProps.put(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, ImmutableList.of(hostActivator)); + felixProps.put(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, List.of(hostActivator)); return felixProps; } - - final long delay = Config.getLongProperty("OSGI_UPLOAD_DEBOUNCE_DELAY_MILLIS", 5000); /** * Overrides the content of the osgi-extra.conf file * - * @param request - * @param response * @throws ServletException * @throws IOException */ @@ -261,23 +261,10 @@ public String getOsgiExtraConfigPath () { */ public void testDryRun (final String osgiPackages) { - final List exportClauses = - invokeParserStandardHeader(osgiPackages); + final List exportClauses = invokeParserStandardHeader(osgiPackages); for (final ParsedHeaderClause clause : exportClauses) { - for (final String packageName : clause.m_paths) { - if (packageName.equals(".")) { - - Logger.error(this, "Exporing '.' is invalid."); - throw new OsgiException("Exporing '.' is invalid."); - } - - if (packageName.length() == 0) { - - Logger.error(this, "Exported package names cannot be zero length.\nPackages: " + osgiPackages); - throw new OsgiException( - "Exported package names cannot be zero length."); - } + validatePackageName(osgiPackages, packageName); } // Check for "version" and "specification-version" attributes @@ -310,6 +297,21 @@ public void testDryRun (final String osgiPackages) { } } + private void validatePackageName(String osgiPackages, String packageName) { + if (packageName.equals(".")) { + + Logger.error(this, "Exporing '.' is invalid."); + throw new OsgiException("Exporing '.' is invalid."); + } + + if (packageName.isEmpty()) { + + Logger.error(this, "Exported package names cannot be zero length.\nPackages: " + osgiPackages); + throw new OsgiException( + "Exported package names cannot be zero length."); + } + } + private List invokeParserStandardHeader (final String osgiPackages) { try { @@ -336,7 +338,7 @@ public synchronized Framework initializeFramework() { long start = System.currentTimeMillis(); // load all properties and set base directory - Properties felixProps = loadConfig(); + final Properties felixProps = loadConfig(); // fetch the 'felix.base.dir' property and check if exists. On the props file the prop needs to for (final String felixDirectory : FELIX_DIRECTORIES) { @@ -351,13 +353,13 @@ public synchronized Framework initializeFramework() { } } - FELIX_EXTRA_PACKAGES_FILE = this.getOsgiExtraConfigPath(); + felixExtraPackagesFile = this.getOsgiExtraConfigPath(); // Verify the bundles are in the right place verifyBundles(felixProps); // Set all OSGI Packages - String extraPackages = getExtraOSGIPackages(); + final String extraPackages = getExtraOSGIPackages(); // Setting the OSGI extra packages property @@ -397,18 +399,62 @@ public synchronized Framework initializeFramework() { Logger.info(this, () -> "osgi felix framework started"); } catch (Exception ex) { - felixFramework=null; + felixFramework = null; Logger.error(this, "Could not create framework: " + ex); throw new RuntimeException(ex); } - System.setProperty(WebKeys.OSGI_ENABLED, "true"); + setOsgiStarted(true); + System.setProperty(WebKeys.OSGI_ENABLED, osgiStarted + ""); System.setProperty(WebKeys.DOTCMS_STARTUP_TIME_OSGI, String.valueOf(System.currentTimeMillis() - start)); + registerActionlets(); + return felixFramework; } + public void registerActionlet(final BundleContext context, + final WorkFlowActionlet actionlet, + final Collection actionlets) { + actionlets.add(actionlet); + + synchronized (osgiLock) { + if (!osgiStarted) { + actionletsToRegister.add(Tuple.of(context, actionlet)); + return; + } + + registerActionlet(context, actionlet); + } + } + + private void setOsgiStarted(final boolean osgiStarted) { + synchronized (osgiLock) { + this.osgiStarted = osgiStarted; + } + } + + private void registerActionlet(final BundleContext context, final WorkFlowActionlet actionlet) { + //Getting the service to register our Actionlet + final ServiceReference serviceRefSelected = + context.getServiceReference(WorkflowAPIOsgiService.class.getName()); + if (serviceRefSelected == null) { + return; + } + + setWorkflowOsgiService((WorkflowAPIOsgiService) context.getService(serviceRefSelected)); + getWorkflowOsgiService().addActionlet(actionlet.getClass()); + + + Logger.info(this, "Added actionlet: " + actionlet.getName()); + OSGIUtil.getInstance().actionletsStopped.remove(actionlet.getClass().getCanonicalName()); + } + + private void registerActionlets() { + actionletsToRegister.forEach(tuple -> registerActionlet(tuple._1, tuple._2)); + } + private void startWatchingUploadFolder(final String uploadFolder) { if(this.isStartedOsgiRestartSchedule.getAndSet(true)) { return; @@ -429,15 +475,11 @@ private void startWatchingUploadFolder(final String uploadFolder) { initialDelay, delay, TimeUnit.SECONDS); } - public void checkUploadFolder() { final ClusterLockManager lockManager = DotConcurrentFactory.getInstance().getClusterLockManager(OSGI_RESTART_LOCK_KEY); checkUploadFolder(new File(OSGIUtil.getInstance().getFelixUploadPath()),lockManager); } - - - - + public void processExports(final String jarFile) { if(!jarFile.equals(StringUtils.sanitizeFileName(jarFile))){ throw new DotRuntimeException("Invalid bundle name: " + jarFile); @@ -455,10 +497,6 @@ public void processExports(final String jarFile) { checkUploadFolder(new File(OSGIUtil.getInstance().getFelixUploadPath()),lockManager); } - - - - // this method is called by the schedule to see if jars has been added to the framework private void checkUploadFolder(final File uploadFolderFile, final ClusterLockManager lockManager) { @@ -775,7 +813,7 @@ public void stopFramework() { } public Boolean isInitialized() { - return null != felixFramework ; + return null != felixFramework; } /** @@ -859,7 +897,7 @@ private Properties loadConfig() { */ public String getExtraOSGIPackages() { - final File extraPackagesFile = new File(FELIX_EXTRA_PACKAGES_FILE); + final File extraPackagesFile = new File(felixExtraPackagesFile); if (!extraPackagesFile.exists() || extraPackagesFile.length()<2) { extraPackagesFile.getParentFile().mkdirs(); @@ -890,8 +928,6 @@ private void createNewExtraPackageFile(final File extraPackagesFile) { } } - - private String readExtraPackagesFiles(final File extraPackagesFile) {