001/* 002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo - initial API and implementation 018 * 019 * $Id$ 020 */ 021 022package org.nuxeo.osgi.application; 023 024import java.io.File; 025import java.io.IOException; 026import java.util.Collection; 027import java.util.List; 028 029import org.nuxeo.common.utils.FileNamePattern; 030import org.nuxeo.osgi.BundleFile; 031import org.nuxeo.osgi.NestedJarBundleFile; 032import org.nuxeo.osgi.OSGiAdapter; 033import org.osgi.framework.BundleException; 034 035/** 036 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 037 */ 038public abstract class ApplicationLoader { 039 040 protected final OSGiAdapter osgi; 041 042 protected boolean extractNestedJARs = false; 043 044 protected boolean scanForNestedJARs = false; 045 046 private FileNamePattern[] patterns = BundleWalker.DEFAULT_PATTERNS; 047 048 private final File tmpDir; 049 050 protected ApplicationLoader(OSGiAdapter osgi) { 051 this.osgi = osgi; 052 tmpDir = new File(osgi.getDataDir(), "nested-bundles"); 053 tmpDir.mkdirs(); 054 } 055 056 public abstract void installBundle(BundleFile bundleFile) throws BundleException; 057 058 public abstract void loadBundle(BundleFile bundleFile); 059 060 public abstract void loadJAR(BundleFile bundleFile); 061 062 public File getNestedBundleDirectory() { 063 return tmpDir; 064 } 065 066 public OSGiAdapter getOSGi() { 067 return osgi; 068 } 069 070 public void setExtractNestedJARs(boolean extractNestedJARs) { 071 this.extractNestedJARs = extractNestedJARs; 072 } 073 074 public boolean getExtractNestedJARs() { 075 return extractNestedJARs; 076 } 077 078 public void setScanForNestedJARs(boolean scanForNestedJARs) { 079 this.scanForNestedJARs = scanForNestedJARs; 080 } 081 082 public boolean getScanForNestedJARs() { 083 return scanForNestedJARs; 084 } 085 086 public void setPatterns(FileNamePattern[] patterns) { 087 this.patterns = patterns; 088 } 089 090 public FileNamePattern[] getPatterns() { 091 return patterns; 092 } 093 094 /** 095 * Scans and loads the given directory for OSGi bundles and regular JARs and fills the given lists appropriately. 096 * <p> 097 * Loading means registering with the given shared class loader each bundle found. 098 * 099 * @param root the directory to recursively scan 100 * @param bundles the list to fill with found bundles 101 * @param jars the list to fill with found jars 102 */ 103 public void load(File root, List<BundleFile> bundles, List<BundleFile> jars) { 104 BundleFileLoader callback = new BundleFileLoader(bundles, jars); 105 BundleWalker visitor = new BundleWalker(callback, patterns); 106 visitor.visit(root); 107 } 108 109 /** 110 * Installs all given bundle deployments. 111 */ 112 public void installAll(Collection<BundleFile> bundleFiles) throws BundleException { 113 for (BundleFile bundleFile : bundleFiles) { 114 installBundle(bundleFile); 115 } 116 } 117 118 /** 119 * Installs all bundles found in the given directory. 120 * <p> 121 * The directory is recursively searched for bundles. 122 * 123 * @param root the tree root 124 */ 125 public void install(File root) { 126 BundleInstaller callback = new BundleInstaller(); 127 BundleWalker visitor = new BundleWalker(callback, patterns); 128 visitor.visit(root); 129 } 130 131 /** 132 * Scans the given directory for OSGi bundles and regular JARs and fills the given lists appropriately. 133 * 134 * @param root the directory to recursively scan 135 * @param bundles the list to fill with found bundles 136 * @param ljars the list to fill with found jars 137 */ 138 public void scan(File root, List<BundleFile> bundles, List<BundleFile> ljars) { 139 BundleFileScanner callback = new BundleFileScanner(bundles, ljars); 140 BundleWalker visitor = new BundleWalker(callback, patterns); 141 visitor.visit(root); 142 } 143 144 /** 145 * Installs bundles as they are discovered by the bundle visitor. 146 * 147 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 148 */ 149 public class BundleInstaller extends DefaultCallback { 150 151 @Override 152 public void visitBundle(BundleFile bundleFile) throws IOException { 153 loadBundle(bundleFile); 154 visitNestedBundles(bundleFile); 155 } 156 157 @Override 158 public void visitJar(BundleFile bundleFile) throws IOException { 159 loadJAR(bundleFile); 160 visitNestedBundles(bundleFile); 161 } 162 163 } 164 165 public class BundleFileScanner extends DefaultCallback { 166 167 final List<BundleFile> bundles; 168 169 final List<BundleFile> jars; 170 171 public BundleFileScanner(List<BundleFile> bundles, List<BundleFile> jars) { 172 this.bundles = bundles; 173 this.jars = jars; 174 } 175 176 @Override 177 public void visitBundle(BundleFile bundleFile) throws IOException { 178 bundles.add(bundleFile); 179 visitNestedBundles(bundleFile); 180 } 181 182 @Override 183 public void visitJar(BundleFile bundleFile) throws IOException { 184 jars.add(bundleFile); 185 visitNestedBundles(bundleFile); 186 } 187 188 public List<BundleFile> getBundles() { 189 return bundles; 190 } 191 192 public List<BundleFile> getJARs() { 193 return jars; 194 } 195 196 } 197 198 public class BundleFileLoader extends DefaultCallback { 199 200 final List<BundleFile> bundles; 201 202 final List<BundleFile> jars; 203 204 public BundleFileLoader(List<BundleFile> bundles, List<BundleFile> jars) { 205 this.bundles = bundles; 206 this.jars = jars; 207 } 208 209 @Override 210 public void visitBundle(BundleFile bundleFile) throws IOException { 211 // System.out.println(">>>> FOUND BUNDLE: "+bundleFile.getFileName()); 212 loadBundle(bundleFile); 213 bundles.add(bundleFile); 214 visitNestedBundles(bundleFile); 215 } 216 217 @Override 218 public void visitJar(BundleFile bundleFile) throws IOException { 219 // System.out.println(">>>> FOUND JAR: "+bundleFile.getFileName()); 220 loadJAR(bundleFile); 221 jars.add(bundleFile); 222 visitNestedBundles(bundleFile); 223 } 224 225 public List<BundleFile> getBundles() { 226 return bundles; 227 } 228 229 public List<BundleFile> getJARs() { 230 return jars; 231 } 232 233 } 234 235 public abstract class DefaultCallback implements BundleWalker.Callback { 236 237 @Override 238 public void visitBundle(BundleFile bundleFile) throws IOException { 239 visitNestedBundles(bundleFile); 240 } 241 242 @Override 243 public void visitJar(BundleFile bundleFile) throws IOException { 244 visitNestedBundles(bundleFile); 245 } 246 247 public void visitNestedBundles(BundleFile bundleFile) throws IOException { 248 if (bundleFile instanceof NestedJarBundleFile) { 249 return; // do not allows more than one level of nesting 250 } 251 if (extractNestedJARs) { 252 Collection<BundleFile> bundles; 253 if (scanForNestedJARs) { 254 bundles = bundleFile.findNestedBundles(tmpDir); 255 } else { // use manifest to find nested jars 256 bundles = bundleFile.getNestedBundles(tmpDir); 257 } 258 if (bundles == null || bundles.isEmpty()) { 259 return; 260 } 261 for (BundleFile bundle : bundles) { 262 if (bundle.getSymbolicName() != null) { 263 visitBundle(bundle); 264 } else { 265 visitJar(bundle); 266 } 267 } 268 } 269 } 270 } 271 272}