001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.osgi.service;
016    
017    import aQute.libg.header.OSGiHeader;
018    
019    import com.liferay.portal.kernel.exception.PortalException;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
023    import com.liferay.portal.kernel.util.ReleaseInfo;
024    import com.liferay.portal.kernel.util.ServiceLoader;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.StringUtil;
027    import com.liferay.portal.kernel.util.Validator;
028    import com.liferay.portal.osgi.BundleListener;
029    import com.liferay.portal.osgi.FrameworkListener;
030    import com.liferay.portal.osgi.OSGiConstants;
031    import com.liferay.portal.osgi.OSGiException;
032    import com.liferay.portal.osgi.ServiceListener;
033    import com.liferay.portal.security.auth.PrincipalException;
034    import com.liferay.portal.security.permission.PermissionChecker;
035    import com.liferay.portal.security.permission.PermissionThreadLocal;
036    import com.liferay.portal.util.PropsValues;
037    import com.liferay.util.UniqueList;
038    
039    import java.io.InputStream;
040    
041    import java.net.URL;
042    
043    import java.util.ArrayList;
044    import java.util.Arrays;
045    import java.util.Collections;
046    import java.util.Enumeration;
047    import java.util.HashMap;
048    import java.util.HashSet;
049    import java.util.Hashtable;
050    import java.util.List;
051    import java.util.Map;
052    import java.util.Set;
053    import java.util.jar.Attributes;
054    import java.util.jar.Manifest;
055    
056    import org.osgi.framework.Bundle;
057    import org.osgi.framework.BundleContext;
058    import org.osgi.framework.BundleException;
059    import org.osgi.framework.Constants;
060    import org.osgi.framework.launch.Framework;
061    import org.osgi.framework.launch.FrameworkFactory;
062    import org.osgi.framework.startlevel.BundleStartLevel;
063    import org.osgi.framework.startlevel.FrameworkStartLevel;
064    
065    import org.springframework.beans.factory.BeanIsAbstractException;
066    import org.springframework.context.ApplicationContext;
067    
068    /**
069     * @author Raymond Augé
070     */
071    public class OSGiServiceUtil {
072    
073            public static Object addBundle(String location) throws PortalException {
074                    return addBundle(location, null);
075            }
076    
077            public static Object addBundle(String location, InputStream inputStream)
078                    throws PortalException {
079    
080                    return _instance._addBundle(location, inputStream);
081            }
082    
083            public static Framework getFramework() {
084                    return _instance._getFramework();
085            }
086    
087            public static String getState(long bundleId) throws PortalException {
088                    return _instance._getState(bundleId);
089            }
090    
091            public static void init() throws Exception {
092                    _instance._init();
093            }
094    
095            public static void registerContext(Object context) {
096                    _instance._registerContext(context);
097            }
098    
099            public static void setBundleStartLevel(long bundleId, int startLevel)
100                    throws PortalException {
101    
102                    _instance._setBundleStartLevel(bundleId, startLevel);
103            }
104    
105            public static void start() throws Exception {
106                    _instance._start();
107            }
108    
109            public static void startBundle(long bundleId) throws PortalException {
110                    _instance._startBundle(bundleId);
111            }
112    
113            public static void startBundle(long bundleId, int options)
114                    throws PortalException {
115    
116                    _instance._startBundle(bundleId, options);
117            }
118    
119            public static void stopFramework() throws Exception {
120                    _instance._stopFramework();
121            }
122    
123            public static void stopRuntime() throws Exception {
124                    _instance._stopRuntime();
125            }
126    
127            public static void stopBundle(long bundleId) throws PortalException {
128                    _instance._stopBundle(bundleId);
129            }
130    
131            public static void stopBundle(long bundleId, int options)
132                    throws PortalException {
133    
134                    _instance._stopBundle(bundleId, options);
135            }
136    
137            public static void uninstallBundle(long bundleId) throws PortalException {
138                    _instance._uninstallBundle(bundleId);
139            }
140    
141            public static void updateBundle(long bundleId) throws PortalException {
142                    _instance._updateBundle(bundleId);
143            }
144    
145            public static void updateBundle(long bundleId, InputStream inputStream)
146                    throws PortalException {
147    
148                    _instance._updateBundle(bundleId, inputStream);
149            }
150    
151            private OSGiServiceUtil() {
152            }
153    
154            private Object _addBundle(String location, InputStream inputStream)
155                    throws PortalException {
156    
157                    _checkPermission();
158    
159                    if (_framework == null) {
160                            return null;
161                    }
162    
163                    BundleContext bundleContext = _framework.getBundleContext();
164    
165                    try {
166                            return bundleContext.installBundle(location, inputStream);
167                    }
168                    catch (BundleException be) {
169                            _log.error(be, be);
170    
171                            throw new OSGiException(be);
172                    }
173            }
174    
175            private Map<String, String> _buildProperties() {
176                    Map<String, String> properties = new HashMap<String, String>();
177    
178                    properties.put(
179                            Constants.BUNDLE_DESCRIPTION, ReleaseInfo.getReleaseInfo());
180                    properties.put(Constants.BUNDLE_NAME, ReleaseInfo.getName());
181                    properties.put(Constants.BUNDLE_VENDOR, ReleaseInfo.getVendor());
182                    properties.put(Constants.BUNDLE_VERSION, ReleaseInfo.getVersion());
183                    properties.put(
184                            Constants.FRAMEWORK_BEGINNING_STARTLEVEL,
185                            String.valueOf(PropsValues.OSGI_FRAMEWORK_BEGINNING_START_LEVEL));
186                    properties.put(
187                            Constants.FRAMEWORK_BUNDLE_PARENT,
188                            Constants.FRAMEWORK_BUNDLE_PARENT_APP);
189                    properties.put(
190                            Constants.FRAMEWORK_STORAGE, PropsValues.OSGI_FRAMEWORK_STORAGE);
191    
192                    UniqueList<String> packages = new UniqueList<String>();
193    
194                    try {
195                            _getBundleExportPackages(
196                                    PropsValues.OSGI_SYSTEM_BUNDLE_EXPORT_PACKAGES, packages);
197                    }
198                    catch (Exception e) {
199                            _log.error(e, e);
200                    }
201    
202                    packages.addAll(Arrays.asList(PropsValues.OSGI_SYSTEM_PACKAGES_EXTRA));
203    
204                    Collections.sort(packages);
205    
206                    properties.put(
207                            Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA,
208                            StringUtil.merge(packages));
209    
210                    return properties;
211            }
212    
213            private void _checkPermission() throws PrincipalException {
214                    PermissionChecker permissionChecker =
215                            PermissionThreadLocal.getPermissionChecker();
216    
217                    if ((permissionChecker == null) || !permissionChecker.isOmniadmin()) {
218                            throw new PrincipalException();
219                    }
220            }
221    
222            private Bundle _getBundle(long bundleId) {
223                    if (_framework == null) {
224                            return null;
225                    }
226    
227                    BundleContext bundleContext = _framework.getBundleContext();
228    
229                    return bundleContext.getBundle(bundleId);
230            }
231    
232            private void _getBundleExportPackages(
233                            String[] bundleSymbolicNames, List<String> packages)
234                    throws Exception {
235    
236                    ClassLoader classLoader = PortalClassLoaderUtil.getClassLoader();
237    
238                    Enumeration<URL> enu = classLoader.getResources("META-INF/MANIFEST.MF");
239    
240                    while (enu.hasMoreElements()) {
241                            URL url = enu.nextElement();
242    
243                            Manifest manifest = new Manifest(url.openStream());
244    
245                            Attributes attributes = manifest.getMainAttributes();
246    
247                            String bundleSymbolicName = attributes.getValue(
248                                    Constants.BUNDLE_SYMBOLICNAME);
249    
250                            if (Validator.isNull(bundleSymbolicName)) {
251                                    continue;
252                            }
253    
254                            for (String curBundleSymbolicName : bundleSymbolicNames) {
255                                    if (!bundleSymbolicName.startsWith(curBundleSymbolicName)) {
256                                            continue;
257                                    }
258    
259                                    String exportPackage = attributes.getValue(
260                                            Constants.EXPORT_PACKAGE);
261    
262                                    Map<String, Map<String, String>> exportPackageMap =
263                                            OSGiHeader.parseHeader(exportPackage);
264    
265                                    for (Map.Entry<String, Map<String, String>> entry :
266                                                    exportPackageMap.entrySet()) {
267    
268                                            String javaPackage = entry.getKey();
269                                            Map<String, String> javaPackageMap = entry.getValue();
270    
271                                            if (javaPackageMap.containsKey("version")) {
272                                                    String version = javaPackageMap.get("version");
273    
274                                                    javaPackage = javaPackage.concat(
275                                                            ";version=\"").concat(version).concat("\"");
276                                            }
277    
278                                            packages.add(javaPackage);
279                                    }
280    
281                                    break;
282                            }
283                    }
284            }
285    
286            private Framework _getFramework() {
287                    return _framework;
288            }
289    
290            private Set<Class<?>> _getInterfaces(Object bean) {
291                    Set<Class<?>> interfaces = new HashSet<Class<?>>();
292    
293                    Class<?> beanClass = bean.getClass();
294    
295                    for (Class<?> interfaceClass : beanClass.getInterfaces()) {
296                            interfaces.add(interfaceClass);
297                    }
298    
299                    while ((beanClass = beanClass.getSuperclass()) != null) {
300                            for (Class<?> interfaceClass : beanClass.getInterfaces()) {
301                                    if (!interfaces.contains(interfaceClass)) {
302                                            interfaces.add(interfaceClass);
303                                    }
304                            }
305                    }
306    
307                    return interfaces;
308            }
309    
310            private String _getState(long bundleId) throws PortalException {
311                    _checkPermission();
312    
313                    Bundle bundle = _getBundle(bundleId);
314    
315                    if (bundle == null) {
316                            throw new OSGiException("No bundle with ID " + bundleId);
317                    }
318    
319                    int state = bundle.getState();
320    
321                    if (state == Bundle.ACTIVE) {
322                            return "active";
323                    }
324                    else if (state == Bundle.INSTALLED) {
325                            return "installed";
326                    }
327                    else if (state == Bundle.RESOLVED) {
328                            return "resolved";
329                    }
330                    else if (state == Bundle.STARTING) {
331                            return "starting";
332                    }
333                    else if (state == Bundle.STOPPING) {
334                            return "stopping";
335                    }
336                    else if (state == Bundle.UNINSTALLED) {
337                            return "uninstalled";
338                    }
339                    else {
340                            return StringPool.BLANK;
341                    }
342            }
343    
344            private void _init() throws Exception {
345                    List<FrameworkFactory> frameworkFactories = ServiceLoader.load(
346                            FrameworkFactory.class);
347    
348                    if (frameworkFactories.isEmpty()) {
349                            return;
350                    }
351    
352                    FrameworkFactory frameworkFactory = frameworkFactories.get(0);
353    
354                    Map<String, String> properties = _buildProperties();
355    
356                    _framework = frameworkFactory.newFramework(properties);
357    
358                    _framework.init();
359    
360                    BundleContext bundleContext = _framework.getBundleContext();
361    
362                    BundleListener bundleListener = new BundleListener();
363    
364                    bundleContext.addBundleListener(bundleListener);
365    
366                    FrameworkListener frameworkListener = new FrameworkListener();
367    
368                    bundleContext.addFrameworkListener(frameworkListener);
369    
370                    ServiceListener serviceListener = new ServiceListener();
371    
372                    bundleContext.addServiceListener(serviceListener);
373    
374                    _framework.start();
375            }
376    
377            private void _registerContext(Object context) {
378                    if ((context == null) || !(context instanceof ApplicationContext) ||
379                            !PropsValues.OSGI_REGISTER_LIFERAY_SERVICES) {
380    
381                            return;
382                    }
383    
384                    ApplicationContext applicationContext = (ApplicationContext)context;
385    
386                    BundleContext bundleContext = _framework.getBundleContext();
387    
388                    for (String beanName : applicationContext.getBeanDefinitionNames()) {
389                            Object bean = null;
390    
391                            try {
392                                    bean = applicationContext.getBean(beanName);
393                            }
394                            catch (BeanIsAbstractException biae) {
395                            }
396                            catch (Exception e) {
397                                    _log.error(e, e);
398                            }
399    
400                            if (bean != null) {
401                                    _registerService(bundleContext, beanName, bean);
402                            }
403                    }
404            }
405    
406            private void _registerService(
407                    BundleContext bundleContext, String beanName, Object bean) {
408    
409                    Set<Class<?>> interfaces = _getInterfaces(bean);
410    
411                    List<String> names = new ArrayList<String>();
412    
413                    for (Class<?> interfaceClass : interfaces) {
414                            names.add(interfaceClass.getName());
415                    }
416    
417                    if (names.isEmpty()) {
418                            return;
419                    }
420    
421                    Hashtable<String,Object> properties = new Hashtable<String, Object>();
422    
423                    properties.put(OSGiConstants.BEAN_ID, beanName);
424                    properties.put(OSGiConstants.ORIGINAL_BEAN, Boolean.TRUE);
425    
426                    bundleContext.registerService(
427                            names.toArray(new String[names.size()]), bean, properties);
428            }
429    
430            private void _setBundleStartLevel(long bundleId, int startLevel)
431                    throws PortalException {
432    
433                    _checkPermission();
434    
435                    Bundle bundle = _getBundle(bundleId);
436    
437                    if (bundle == null) {
438                            throw new OSGiException("No bundle with ID " + bundleId);
439                    }
440    
441                    BundleStartLevel bundleStartLevel = bundle.adapt(
442                            BundleStartLevel.class);
443    
444                    bundleStartLevel.setStartLevel(startLevel);
445            }
446    
447            private void _start() throws Exception {
448                    if (_framework == null) {
449                            return;
450                    }
451    
452                    FrameworkStartLevel frameworkStartLevel = _framework.adapt(
453                            FrameworkStartLevel.class);
454    
455                    frameworkStartLevel.setStartLevel(
456                            PropsValues.OSGI_FRAMEWORK_RUNTIME_START_LEVEL,
457                            (FrameworkListener[])null);
458            }
459    
460            private void _startBundle(long bundleId) throws PortalException {
461                    _checkPermission();
462    
463                    Bundle bundle = _getBundle(bundleId);
464    
465                    if (bundle == null) {
466                            throw new OSGiException("No bundle with ID " + bundleId);
467                    }
468    
469                    try {
470                            bundle.start();
471                    }
472                    catch (BundleException be) {
473                            _log.error(be, be);
474    
475                            throw new OSGiException(be);
476                    }
477            }
478    
479            private void _startBundle(long bundleId, int options)
480                    throws PortalException {
481    
482                    _checkPermission();
483    
484                    Bundle bundle = _getBundle(bundleId);
485    
486                    if (bundle == null) {
487                            throw new OSGiException("No bundle with ID " + bundleId);
488                    }
489    
490                    try {
491                            bundle.start(options);
492                    }
493                    catch (BundleException be) {
494                            _log.error(be, be);
495    
496                            throw new OSGiException(be);
497                    }
498            }
499    
500            private void _stopFramework() throws Exception {
501                    if (_framework == null) {
502                            return;
503                    }
504    
505                    _framework.stop();
506            }
507    
508            private void _stopRuntime() throws Exception {
509                    if (_framework == null) {
510                            return;
511                    }
512    
513                    FrameworkStartLevel frameworkStartLevel = _framework.adapt(
514                            FrameworkStartLevel.class);
515    
516                    frameworkStartLevel.setStartLevel(
517                            PropsValues.OSGI_FRAMEWORK_BEGINNING_START_LEVEL,
518                            (FrameworkListener[])null);
519            }
520    
521            private void _stopBundle(long bundleId) throws PortalException {
522                    _checkPermission();
523    
524                    Bundle bundle = _getBundle(bundleId);
525    
526                    if (bundle == null) {
527                            throw new OSGiException("No bundle with ID " + bundleId);
528                    }
529    
530                    try {
531                            bundle.stop();
532                    }
533                    catch (BundleException be) {
534                            _log.error(be, be);
535    
536                            throw new OSGiException(be);
537                    }
538            }
539    
540            private void _stopBundle(long bundleId, int options)
541                    throws PortalException {
542    
543                    _checkPermission();
544    
545                    Bundle bundle = _getBundle(bundleId);
546    
547                    if (bundle == null) {
548                            throw new OSGiException("No bundle with ID " + bundleId);
549                    }
550    
551                    try {
552                            bundle.stop(options);
553                    }
554                    catch (BundleException be) {
555                            _log.error(be, be);
556    
557                            throw new OSGiException(be);
558                    }
559            }
560    
561            private void _uninstallBundle(long bundleId) throws PortalException {
562                    _checkPermission();
563    
564                    Bundle bundle = _getBundle(bundleId);
565    
566                    if (bundle == null) {
567                            throw new OSGiException("No bundle with ID " + bundleId);
568                    }
569    
570                    try {
571                            bundle.uninstall();
572                    }
573                    catch (BundleException be) {
574                            _log.error(be, be);
575    
576                            throw new OSGiException(be);
577                    }
578            }
579    
580            private void _updateBundle(long bundleId) throws PortalException {
581                    _checkPermission();
582    
583                    Bundle bundle = _getBundle(bundleId);
584    
585                    if (bundle == null) {
586                            throw new OSGiException("No bundle with ID " + bundleId);
587                    }
588    
589                    try {
590                            bundle.update();
591                    }
592                    catch (BundleException be) {
593                            _log.error(be, be);
594    
595                            throw new OSGiException(be);
596                    }
597            }
598    
599            private void _updateBundle(long bundleId, InputStream inputStream)
600                    throws PortalException {
601    
602                    _checkPermission();
603    
604                    Bundle bundle = _getBundle(bundleId);
605    
606                    if (bundle == null) {
607                            throw new OSGiException("No bundle with ID " + bundleId);
608                    }
609    
610                    try {
611                            bundle.update(inputStream);
612                    }
613                    catch (BundleException be) {
614                            _log.error(be, be);
615    
616                            throw new OSGiException(be);
617                    }
618            }
619    
620            private static Log _log = LogFactoryUtil.getLog(OSGiServiceUtil.class);
621    
622            private static OSGiServiceUtil _instance = new OSGiServiceUtil();
623    
624            private Framework _framework;
625    
626    }