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