
org.glassfish.osgijavaeebase.JavaEEExtender Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2009-2012 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package org.glassfish.osgijavaeebase;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.ServiceRegistration;
import org.osgi.util.tracker.BundleTracker;
import org.osgi.util.tracker.BundleTrackerCustomizer;
import java.util.Map;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* This extender is responsible for detecting and deploying any Java EE OSGi bundle.
*
* @author [email protected]
*/
public class JavaEEExtender implements Extender {
/*
* Implementation Note: All methods are synchronized, because we don't allow the extender to stop while it
* is deploying or undeploying something. Similarly, while it is being stopped, we don't want it to deploy
* or undeploy something.
* After receiving the event, it spwans a separate thread to carry out the task so that we don't
* spend long time in the synchronous event listener. More over, that can lead to deadlocks as observed
* in https://glassfish.dev.java.net/issues/show_bug.cgi?id=14313.
*/
private static final String DEPLOYMENT_TIMEOUT =
"org.glassfish.osgijavaeebase.deployment.timeout";
private volatile OSGiContainer c;
private static final Logger logger =
Logger.getLogger(JavaEEExtender.class.getPackage().getName());
private BundleContext context;
private ServiceRegistration reg;
private BundleTracker tracker;
private ExecutorService executorService;
public JavaEEExtender(BundleContext context) {
this.context = context;
}
public synchronized void start() {
executorService = Executors.newSingleThreadExecutor();
c = new OSGiContainer(context);
c.init();
reg = context.registerService(OSGiContainer.class.getName(), c, null);
tracker = new BundleTracker(context, Bundle.ACTIVE | Bundle.STARTING, new HybridBundleTrackerCustomizer());
tracker.open();
}
public synchronized void stop() {
if (c == null) return;
OSGiContainer tmp = c;
c = null;
tmp.shutdown();
if (tracker != null) tracker.close();
tracker = null;
reg.unregister();
reg = null;
executorService.shutdownNow();
}
private synchronized OSGiApplicationInfo deploy(Bundle b) {
if (!isStarted()) return null;
try {
return c.deploy(b);
}
catch (Throwable e) {
logger.logp(Level.SEVERE, "JavaEEExtender", "deploy",
"Exception deploying bundle {0}",
new Object[]{b.getLocation()});
logger.logp(Level.SEVERE, "JavaEEExtender", "deploy",
"Exception Stack Trace", e);
}
return null;
}
private synchronized void undeploy(Bundle b) {
if (!isStarted()) return;
try {
if (c.isDeployed(b)) {
c.undeploy(b);
}
}
catch (Exception e) {
logger.logp(Level.SEVERE, "JavaEEExtender", "undeploy",
"Exception undeploying bundle {0}",
new Object[]{b.getLocation()});
logger.logp(Level.SEVERE, "JavaEEExtender", "undeploy",
"Exception Stack Trace", e);
}
}
private boolean isStarted() {
// This method is deliberately made non-synchronized, because it is called from tracker customizer
return c!= null;
}
private class HybridBundleTrackerCustomizer implements BundleTrackerCustomizer {
private Map> deploymentTasks =
new ConcurrentHashMap>();
public Object addingBundle(final Bundle bundle, BundleEvent event) {
if (!isStarted()) return null;
final int state = bundle.getState();
if (isReady(event, state)) {
Future future = executorService.submit(new Callable() {
@Override
public OSGiApplicationInfo call() throws Exception {
return deploy(bundle);
}
});
deploymentTasks.put(bundle.getBundleId(), future);
return bundle;
}
return null;
}
/**
* Bundle is ready when its state is ACTIVE or, when a lazy activation policy is used, STARTING
* @param event
* @param state
* @return
*/
private boolean isReady(BundleEvent event, int state) {
return state == Bundle.ACTIVE ||
(state == Bundle.STARTING && (event != null && event.getType() == BundleEvent.LAZY_ACTIVATION));
}
public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) {
}
public void removedBundle(final Bundle bundle, BundleEvent event, Object object) {
if (!isStarted()) return;
Future deploymentTask = deploymentTasks.remove(bundle.getBundleId());
if (deploymentTask == null) {
// We have never seen this bundle before. Ideally we should never get here.
assert(false);
return;
}
try {
OSGiApplicationInfo deployedApp = null;
try {
deployedApp = deploymentTask.get(getDeploymentTimeout(), TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
logger.logp(Level.FINE, "JavaEEExtender$HybridBundleTrackerCustomizer", "removedBundle",
"Undeployer times out waiting for deployment to finish for bundle " + bundle, e);
boolean isCancelled = deploymentTask.cancel(true);
if (!isCancelled) {
// cancellation of timer won't be successful if the deployer has finished by the time we attempt to cancel
deployedApp = deploymentTask.get();
} else {
logger.logp(Level.INFO, "JavaEEExtender$HybridBundleTrackerCustomizer", "removedBundle",
"isCancelled = {0}", new Object[]{isCancelled});
}
}
// It is not sufficient to check the future only, as the DeployerAddedThread currently deploys
// without our knowledge, so we must also check isDeployed().
// More over, if the task has been cancelled, deployedApp will be null, but the deployer might have
// almost deployed the bundle as seen issue GLASSFISH-18159. In such case, we have to check the
// deployment status by calling isDeployed().
if (deployedApp != null || c.isDeployed(bundle)) {
undeploy(bundle); // undeploy synchronously to avoid any deadlock. See GF issue #
}
} catch (InterruptedException e) {
throw new RuntimeException(e); // TODO(Sahoo): Proper Exception Handling
} catch (ExecutionException e) {
logger.logp(Level.FINE, "JavaEEExtender$HybridBundleTrackerCustomizer", "removedBundle", "e = {0}", new Object[]{e});
}
}
public long getDeploymentTimeout() {
long timeOut;
String time = context.getProperty(DEPLOYMENT_TIMEOUT);
if (time != null) {
timeOut = Long.valueOf(time);
} else {
timeOut = 10000;
}
return timeOut;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy