View Javadoc
1   /*
2    * Copyright (C) 2007-2012 Argeo GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.argeo.eclipse.spring;
17  
18  import static java.text.MessageFormat.format;
19  
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  import org.eclipse.core.runtime.Platform;
23  import org.osgi.framework.Bundle;
24  import org.osgi.framework.BundleContext;
25  import org.osgi.framework.BundleException;
26  import org.osgi.framework.FrameworkUtil;
27  import org.osgi.framework.InvalidSyntaxException;
28  import org.osgi.util.tracker.ServiceTracker;
29  import org.springframework.context.ApplicationContext;
30  
31  /**
32   * Tracks Spring application context published as services.
33   * 
34   * @author Heiko Seeberger
35   * @author Mathieu Baudier
36   */
37  class ApplicationContextTracker {
38  	private final static Log log = LogFactory
39  			.getLog(ApplicationContextTracker.class);
40  
41  	private static final String FILTER = "(&(objectClass=org.springframework.context.ApplicationContext)" //$NON-NLS-1$
42  			+ "(org.springframework.context.service.name={0}))"; //$NON-NLS-1$
43  
44  	public final static String APPLICATION_CONTEXT_TRACKER_TIMEOUT = "org.argeo.eclipse.spring.applicationContextTrackerTimeout";
45  
46  	private static Long defaultTimeout = Long.parseLong(System.getProperty(
47  			APPLICATION_CONTEXT_TRACKER_TIMEOUT, "30000"));
48  
49  	@SuppressWarnings("rawtypes")
50  	private ServiceTracker applicationContextServiceTracker;
51  
52  	/**
53  	 * @param contributorBundle
54  	 *            OSGi bundle for which the Spring application context is to be
55  	 *            tracked. Must not be null!
56  	 * @param factoryBundleContext
57  	 *            BundleContext object which can be used to track services
58  	 * @throws IllegalArgumentException
59  	 *             if the given bundle is null.
60  	 */
61  	@SuppressWarnings({ "unchecked", "rawtypes" })
62  	public ApplicationContextTracker(final Bundle contributorBundle,
63  			final BundleContext factoryBundleContext) {
64  		final String filter = format(FILTER,
65  				contributorBundle.getSymbolicName());
66  		try {
67  			applicationContextServiceTracker = new ServiceTracker(
68  					factoryBundleContext, FrameworkUtil.createFilter(filter),
69  					null);
70  			// applicationContextServiceTracker.open();
71  		} catch (final InvalidSyntaxException e) {
72  			e.printStackTrace();
73  		}
74  	}
75  
76  	public void open() {
77  		if (applicationContextServiceTracker != null) {
78  			applicationContextServiceTracker.open();
79  		}
80  	}
81  
82  	public void close() {
83  		if (applicationContextServiceTracker != null) {
84  			applicationContextServiceTracker.close();
85  		}
86  	}
87  
88  	public ApplicationContext getApplicationContext() {
89  		ApplicationContext applicationContext = null;
90  		if (applicationContextServiceTracker != null) {
91  			try {
92  				applicationContext = (ApplicationContext) applicationContextServiceTracker
93  						.waitForService(defaultTimeout);
94  			} catch (InterruptedException e) {
95  				e.printStackTrace();
96  			}
97  		}
98  		return applicationContext;
99  	}
100 
101 	@Override
102 	protected void finalize() throws Throwable {
103 		close();
104 		super.finalize();
105 	}
106 
107 	static ApplicationContext getApplicationContext(String bundleSymbolicName) {
108 		Bundle contributorBundle = Platform.getBundle(bundleSymbolicName);
109 		return getApplicationContext(contributorBundle);
110 	}
111 
112 	static ApplicationContext getApplicationContext(
113 			final Bundle contributorBundle) {
114 		if (log.isTraceEnabled())
115 			log.trace("Get application context for bundle " + contributorBundle);
116 
117 		// Start if not yet started (also if in STARTING state, may be lazy)
118 		if (contributorBundle.getState() != Bundle.ACTIVE) {
119 			if (log.isTraceEnabled())
120 				log.trace("Starting bundle: "
121 						+ contributorBundle.getSymbolicName());
122 			// Thread startBundle = new Thread("Start bundle "
123 			// + contributorBundle.getSymbolicName()) {
124 			// public void run() {
125 			try {
126 				contributorBundle.start();
127 			} catch (BundleException e) {
128 				log.error("Cannot start bundle " + contributorBundle, e);
129 			}
130 			// }
131 			// };
132 			// startBundle.start();
133 			// try {
134 			// startBundle.join(10 * 1000l);
135 			// } catch (InterruptedException e) {
136 			// // silent
137 			// }
138 		}
139 
140 		final ApplicationContextTracker applicationContextTracker = new ApplicationContextTracker(
141 				contributorBundle, contributorBundle.getBundleContext());
142 		ApplicationContext applicationContext = null;
143 		try {
144 			applicationContextTracker.open();
145 			applicationContext = applicationContextTracker
146 					.getApplicationContext();
147 		} finally {
148 			applicationContextTracker.close();
149 		}
150 		return applicationContext;
151 	}
152 }