/* * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: * Nuxeo - initial API and implementation * * $Id$ */ package org.nuxeo.osgi.application; import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.List; import org.nuxeo.common.utils.FileNamePattern; import org.nuxeo.osgi.BundleFile; import org.nuxeo.osgi.NestedJarBundleFile; import org.nuxeo.osgi.OSGiAdapter; import org.osgi.framework.BundleException; /** * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> */ public abstract class ApplicationLoader { protected final OSGiAdapter osgi; protected boolean extractNestedJARs = false; protected boolean scanForNestedJARs = false; private FileNamePattern[] patterns = BundleWalker.DEFAULT_PATTERNS; private final File tmpDir; protected ApplicationLoader(OSGiAdapter osgi) { this.osgi = osgi; tmpDir = new File(osgi.getDataDir(), "nested-bundles"); tmpDir.mkdirs(); } public abstract void installBundle(BundleFile bundleFile) throws BundleException; public abstract void loadBundle(BundleFile bundleFile); public abstract void loadJAR(BundleFile bundleFile); public File getNestedBundleDirectory() { return tmpDir; } public OSGiAdapter getOSGi() { return osgi; } public void setExtractNestedJARs(boolean extractNestedJARs) { this.extractNestedJARs = extractNestedJARs; } public boolean getExtractNestedJARs() { return extractNestedJARs; } public void setScanForNestedJARs(boolean scanForNestedJARs) { this.scanForNestedJARs = scanForNestedJARs; } public boolean getScanForNestedJARs() { return scanForNestedJARs; } public void setPatterns(FileNamePattern[] patterns) { this.patterns = patterns; } public FileNamePattern[] getPatterns() { return patterns; } /** * Scans and loads the given directory for OSGi bundles and regular JARs and fills the given lists appropriately. * <p> * Loading means registering with the given shared class loader each bundle found. * * @param root the directory to recursively scan * @param bundles the list to fill with found bundles * @param jars the list to fill with found jars */ public void load(File root, List<BundleFile> bundles, List<BundleFile> jars) { BundleFileLoader callback = new BundleFileLoader(bundles, jars); BundleWalker visitor = new BundleWalker(callback, patterns); visitor.visit(root); } /** * Installs all given bundle deployments. * * @param bundleFiles * @throws BundleException */ public void installAll(Collection<BundleFile> bundleFiles) throws BundleException { for (BundleFile bundleFile : bundleFiles) { installBundle(bundleFile); } } /** * Installs all bundles found in the given directory. * <p> * The directory is recursively searched for bundles. * * @param root the tree root */ public void install(File root) { BundleInstaller callback = new BundleInstaller(); BundleWalker visitor = new BundleWalker(callback, patterns); visitor.visit(root); } /** * Scans the given directory for OSGi bundles and regular JARs and fills the given lists appropriately. * * @param root the directory to recursively scan * @param bundles the list to fill with found bundles * @param ljars the list to fill with found jars */ public void scan(File root, List<BundleFile> bundles, List<BundleFile> ljars) { BundleFileScanner callback = new BundleFileScanner(bundles, ljars); BundleWalker visitor = new BundleWalker(callback, patterns); visitor.visit(root); } /** * Installs bundles as they are discovered by the bundle visitor. * * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> */ public class BundleInstaller extends DefaultCallback { @Override public void visitBundle(BundleFile bundleFile) throws IOException { loadBundle(bundleFile); visitNestedBundles(bundleFile); } @Override public void visitJar(BundleFile bundleFile) throws IOException { loadJAR(bundleFile); visitNestedBundles(bundleFile); } } public class BundleFileScanner extends DefaultCallback { final List<BundleFile> bundles; final List<BundleFile> jars; public BundleFileScanner(List<BundleFile> bundles, List<BundleFile> jars) { this.bundles = bundles; this.jars = jars; } @Override public void visitBundle(BundleFile bundleFile) throws IOException { bundles.add(bundleFile); visitNestedBundles(bundleFile); } @Override public void visitJar(BundleFile bundleFile) throws IOException { jars.add(bundleFile); visitNestedBundles(bundleFile); } public List<BundleFile> getBundles() { return bundles; } public List<BundleFile> getJARs() { return jars; } } public class BundleFileLoader extends DefaultCallback { final List<BundleFile> bundles; final List<BundleFile> jars; public BundleFileLoader(List<BundleFile> bundles, List<BundleFile> jars) { this.bundles = bundles; this.jars = jars; } @Override public void visitBundle(BundleFile bundleFile) throws IOException { // System.out.println(">>>> FOUND BUNDLE: "+bundleFile.getFileName()); loadBundle(bundleFile); bundles.add(bundleFile); visitNestedBundles(bundleFile); } @Override public void visitJar(BundleFile bundleFile) throws IOException { // System.out.println(">>>> FOUND JAR: "+bundleFile.getFileName()); loadJAR(bundleFile); jars.add(bundleFile); visitNestedBundles(bundleFile); } public List<BundleFile> getBundles() { return bundles; } public List<BundleFile> getJARs() { return jars; } } public abstract class DefaultCallback implements BundleWalker.Callback { @Override public void visitBundle(BundleFile bundleFile) throws IOException { visitNestedBundles(bundleFile); } @Override public void visitJar(BundleFile bundleFile) throws IOException { visitNestedBundles(bundleFile); } public void visitNestedBundles(BundleFile bundleFile) throws IOException { if (bundleFile instanceof NestedJarBundleFile) { return; // do not allows more than one level of nesting } if (extractNestedJARs) { Collection<BundleFile> bundles; if (scanForNestedJARs) { bundles = bundleFile.findNestedBundles(tmpDir); } else { // use manifest to find nested jars bundles = bundleFile.getNestedBundles(tmpDir); } if (bundles == null || bundles.isEmpty()) { return; } for (BundleFile bundle : bundles) { if (bundle.getSymbolicName() != null) { visitBundle(bundle); } else { visitJar(bundle); } } } } } }