001/*
002 * (C) Copyright 2006-2014 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nuxeo - initial API and implementation
016 *     tdelprat, jcarsique
017 */
018
019package org.nuxeo.ecm.admin.runtime;
020
021import java.io.File;
022import java.io.IOException;
023import java.io.InputStream;
024import java.util.ArrayList;
025import java.util.Collection;
026import java.util.Collections;
027import java.util.Enumeration;
028import java.util.List;
029import java.util.PropertyResourceBundle;
030import java.util.zip.ZipEntry;
031import java.util.zip.ZipFile;
032
033import org.apache.commons.logging.Log;
034import org.apache.commons.logging.LogFactory;
035import org.nuxeo.connect.update.Version;
036import org.nuxeo.osgi.BundleFile;
037import org.nuxeo.osgi.BundleImpl;
038import org.nuxeo.osgi.JarBundleFile;
039import org.nuxeo.runtime.RuntimeService;
040import org.nuxeo.runtime.api.Framework;
041import org.nuxeo.runtime.model.RegistrationInfo;
042import org.osgi.framework.Bundle;
043
044/**
045 * Extracts information about the Bundles currently deployed in Nuxeo Runtime
046 *
047 * @author tiry
048 */
049public class RuntimeInstrospection {
050
051    protected static final Log log = LogFactory.getLog(RuntimeInstrospection.class);
052
053    protected static SimplifiedServerInfo info;
054
055    protected static List<String> bundleIds;
056
057    public static synchronized SimplifiedServerInfo getInfo() {
058        if (info == null) {
059            RuntimeService runtime = Framework.getRuntime();
060            Collection<RegistrationInfo> registrations = runtime.getComponentManager().getRegistrations();
061            bundleIds = new ArrayList<>();
062            List<SimplifiedBundleInfo> bundles = new ArrayList<>();
063            for (RegistrationInfo ri : registrations) {
064                Bundle bundle = ri.getContext().getBundle();
065                if (bundle != null && !bundleIds.contains(bundle.getSymbolicName())) {
066                    SimplifiedBundleInfo bi = getBundleSimplifiedInfo(bundle);
067                    bundleIds.add(bundle.getSymbolicName());
068                    if (bi != null) {
069                        bundles.add(bi);
070                    }
071                }
072            }
073            Collections.sort(bundles);
074            info = new SimplifiedServerInfo();
075            info.setBundleInfos(bundles);
076            info.setRuntimeVersion(runtime.getVersion().toString());
077            info.setWarnings(runtime.getWarnings());
078        }
079        return info;
080    }
081
082    public static List<String> getBundleIds() {
083        if (bundleIds == null) {
084            getInfo();
085        }
086        return bundleIds;
087    }
088
089    protected static SimplifiedBundleInfo getBundleSimplifiedInfo(Bundle bundle) {
090        if (!(bundle instanceof BundleImpl)) {
091            return null;
092        }
093        BundleImpl nxBundle = (BundleImpl) bundle;
094        BundleFile file = nxBundle.getBundleFile();
095        File jarFile = null;
096        if (file instanceof JarBundleFile) {
097            JarBundleFile jar = (JarBundleFile) file;
098            jarFile = jar.getFile();
099        }
100        if (jarFile == null || jarFile.isDirectory()) {
101            return null;
102        }
103        SimplifiedBundleInfo result = null;
104        try (ZipFile zFile = new ZipFile(jarFile)) {
105            // Look for a pom.properties to extract its Maven version
106            Enumeration<ZipEntry> entries = (Enumeration<ZipEntry>) zFile.entries();
107            while (entries.hasMoreElements()) {
108                ZipEntry entry = entries.nextElement();
109                if (entry.getName().endsWith("pom.properties")) {
110                    try (InputStream pomStream = zFile.getInputStream(entry)) {
111                        PropertyResourceBundle prb = new PropertyResourceBundle(pomStream);
112                        String version = prb.getString("version");
113                        result = new SimplifiedBundleInfo(bundle.getSymbolicName(), version);
114                    }
115                    break;
116                }
117            }
118        } catch (IOException e) {
119            log.debug(e.getMessage(), e);
120        }
121        if (result == null) {
122            // Fall back on the filename to extract a version
123            try {
124                Version version = new Version(jarFile.getName());
125                result = new SimplifiedBundleInfo(bundle.getSymbolicName(), version.toString());
126            } catch (NumberFormatException e) {
127                log.debug(e.getMessage());
128            }
129        }
130        if (result == null) {
131            // Fall back on the MANIFEST Bundle-Version
132            try {
133                org.osgi.framework.Version version = bundle.getVersion();
134                result = new SimplifiedBundleInfo(bundle.getSymbolicName(), version.toString());
135            } catch (RuntimeException e) {
136                log.debug(e.getMessage());
137                result = new SimplifiedBundleInfo(bundle.getSymbolicName(), "unknown");
138            }
139        }
140        return result;
141    }
142}