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