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.slc.equinox.unit;
17  
18  import java.util.ArrayList;
19  import java.util.HashMap;
20  import java.util.List;
21  import java.util.Map;
22  
23  import junit.framework.TestCase;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.argeo.osgi.boot.OsgiBoot;
28  import org.argeo.slc.SlcException;
29  import org.eclipse.core.runtime.adaptor.EclipseStarter;
30  import org.eclipse.gemini.blueprint.util.OsgiStringUtils;
31  import org.osgi.framework.Bundle;
32  import org.osgi.framework.BundleContext;
33  import org.osgi.framework.InvalidSyntaxException;
34  import org.osgi.framework.ServiceReference;
35  import org.springframework.context.ApplicationContext;
36  
37  @SuppressWarnings("restriction")
38  public abstract class AbstractOsgiRuntimeTestCase extends TestCase {
39  	private final static Log log = LogFactory
40  			.getLog(AbstractOsgiRuntimeTestCase.class);
41  
42  	protected OsgiBoot osgiBoot = null;
43  
44  	protected void installBundles() throws Exception {
45  
46  	}
47  
48  	public void setUp() throws Exception {
49  		// To avoid xerces from the classpath being detected as the provider
50  		System
51  				.setProperty("javax.xml.parsers.DocumentBuilderFactory",
52  						"com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");
53  		System.setProperty("javax.xml.parsers.SAXParserFactory",
54  				"com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl");
55  
56  		BundleContext bundleContext = startRuntime();
57  		osgiBoot = new OsgiBoot(bundleContext);
58  		log.info("OSGi runtime started.");
59  
60  		installBundles();
61  
62  		List<String> bundlesToStart = getBundlesToStart();
63  		osgiBoot.startBundles(bundlesToStart);
64  		waitAllBundlesOk(bundlesToStart);
65  		if (log.isTraceEnabled())
66  			listInstalledBundles();
67  	}
68  
69  	public void tearDown() throws Exception {
70  		osgiBoot = null;
71  		stopRuntime();
72  		log.info("OSGi runtime stopped.");
73  	}
74  
75  	protected BundleContext startRuntime() throws Exception {
76  		String[] args = { "-console", "-clean" };
77  		BundleContext bundleContext = EclipseStarter.startup(args, null);
78  		return bundleContext;
79  	}
80  
81  	protected void stopRuntime() throws Exception {
82  		EclipseStarter.shutdown();
83  	}
84  
85  	protected List<String> getBundlesToStart() {
86  		return new ArrayList<String>();
87  	}
88  
89  	protected void listInstalledBundles() {
90  		BundleContext bundleContext = osgiBoot.getBundleContext();
91  		Bundle[] bundles = bundleContext.getBundles();
92  		for (int i = 0; i < bundles.length; i++) {
93  			System.out.println(OsgiStringUtils.nullSafeSymbolicName(bundles[i])
94  					+ " [" + OsgiStringUtils.bundleStateAsString(bundles[i])
95  					+ "] " + bundles[i].getLocation());
96  		}
97  
98  	}
99  
100 	protected Map<Bundle, ApplicationContext> getOsgiApplicationContexts()
101 			throws Exception {
102 		Map<Bundle, ApplicationContext> map = new HashMap<Bundle, ApplicationContext>();
103 		BundleContext bundleContext = osgiBoot.getBundleContext();
104 		ServiceReference[] srs = bundleContext.getServiceReferences(
105 				ApplicationContext.class.getName(), null);
106 		for (ServiceReference sr : srs) {
107 			ApplicationContext context = (ApplicationContext) bundleContext
108 					.getService(sr);
109 			map.put(sr.getBundle(), context);
110 		}
111 		return map;
112 	}
113 
114 	/** Wait for all bundles to be either RESOLVED or ACTIVE. */
115 	protected void waitAllBundlesOk(List<String> bundlesToStart) {
116 		BundleContext bundleContext = osgiBoot.getBundleContext();
117 		long begin = System.currentTimeMillis();
118 		long duration = 0;
119 		boolean allBundlesOk = true;
120 		StringBuffer badBundles = null;
121 		while (duration < getResolvedTimeout()) {
122 			badBundles = new StringBuffer();
123 			for (Bundle bundle : bundleContext.getBundles()) {
124 				if (bundle.getSymbolicName() != null
125 						&& bundle.getSymbolicName().startsWith(
126 								"org.eclipse.jdt")) {
127 					// don't check Eclipse SDK bundles
128 					continue;
129 				}
130 
131 				if (bundle.getState() == Bundle.INSTALLED) {
132 					allBundlesOk = false;
133 					badBundles
134 							.append(OsgiStringUtils
135 									.nullSafeSymbolicName(bundle)
136 									+ " ["
137 									+ OsgiStringUtils
138 											.bundleStateAsString(bundle) + "]");
139 				}
140 
141 				if (bundlesToStart.contains(bundle.getSymbolicName())
142 						&& bundle.getState() != Bundle.ACTIVE) {
143 					allBundlesOk = false;
144 					badBundles.append(OsgiStringUtils
145 							.nullSafeSymbolicName(bundle)
146 							+ " ["
147 							+ OsgiStringUtils.bundleStateAsString(bundle)
148 							+ "]\n");
149 				}
150 			}
151 
152 			if (allBundlesOk)
153 				break;// while
154 
155 			sleep(1000);
156 
157 			duration = System.currentTimeMillis() - begin;
158 		}
159 
160 		if (!allBundlesOk) {
161 			listInstalledBundles();
162 			throw new SlcException(
163 					"Some bundles are not at the proper status:\n" + badBundles);
164 		}
165 	}
166 
167 	/**
168 	 * Make sure that the application context of the started bundles starting
169 	 * with this prefix are properly initialized
170 	 */
171 	protected void assertStartedBundlesApplicationContext(
172 			String bundleSymbolicNamesPrefix) {
173 		List<String> bundlesToStart = getBundlesToStart();
174 		for (String bundleSName : bundlesToStart) {
175 			if (bundleSName.startsWith(bundleSymbolicNamesPrefix))
176 				assertBundleApplicationContext(bundleSName);
177 		}
178 	}
179 
180 	/**
181 	 * Make sure that the application context of this bundle is properly
182 	 * initialized
183 	 */
184 	protected void assertBundleApplicationContext(String bundleSymbolicName) {
185 		String filter = "(Bundle-SymbolicName=" + bundleSymbolicName + ")";
186 		// Wait for application context to be ready
187 		try {
188 			ServiceReference[] srs = getServiceRefSynchronous(
189 					ApplicationContext.class.getName(), filter);
190 			if (srs == null)
191 				throw new SlcException("No application context for "
192 						+ bundleSymbolicName);
193 		} catch (InvalidSyntaxException e) {
194 			throw new SlcException(
195 					"Unexpected exception when looking for application context for bundle "
196 							+ bundleSymbolicName, e);
197 		}
198 		log.info("Application context of bundle " + bundleSymbolicName
199 				+ " is initalized.");
200 	}
201 
202 	protected ServiceReference[] getServiceRefSynchronous(String clss,
203 			String filter) throws InvalidSyntaxException {
204 		// FIXME: factorize
205 		if (log.isTraceEnabled())
206 			log.debug("Filter: '" + filter + "'");
207 		ServiceReference[] sfs = null;
208 		boolean waiting = true;
209 		long begin = System.currentTimeMillis();
210 		do {
211 			sfs = getBundleContext().getServiceReferences(clss, filter);
212 
213 			if (sfs != null)
214 				waiting = false;
215 
216 			sleep(100);
217 			if (System.currentTimeMillis() - begin > getDefaultTimeout())
218 				throw new SlcException("Search of services " + clss
219 						+ " with filter " + filter + " timed out.");
220 		} while (waiting);
221 
222 		return sfs;
223 	}
224 
225 	protected BundleContext getBundleContext() {
226 		return osgiBoot.getBundleContext();
227 	}
228 
229 	/** Default is 30s */
230 	protected long getResolvedTimeout() {
231 		return 30 * 1000l;
232 	}
233 
234 	/** Default is 10s */
235 	protected long getDefaultTimeout() {
236 		return 10 * 1000l;
237 	}
238 
239 	final protected void sleep(long duration) {
240 		try {
241 			Thread.sleep(1000);
242 		} catch (InterruptedException e) {
243 			// silent
244 		}
245 	}
246 }