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 * bstefanescu 018 * 019 * $Id$ 020 */ 021 022package org.nuxeo.osgi.application; 023 024import java.io.BufferedReader; 025import java.io.BufferedWriter; 026import java.io.File; 027import java.io.FileReader; 028import java.io.FileWriter; 029import java.io.IOException; 030import java.util.ArrayList; 031import java.util.List; 032import java.util.jar.JarFile; 033 034import org.nuxeo.osgi.BundleFile; 035import org.nuxeo.osgi.DirectoryBundleFile; 036import org.nuxeo.osgi.JarBundleFile; 037import org.osgi.framework.BundleException; 038 039/** 040 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 041 */ 042public class ApplicationBundleLoader { 043 044 protected StandaloneBundleLoader bundleLoader; 045 046 protected final StandaloneApplication app; 047 048 protected boolean useCache = false; 049 050 protected boolean extractNestedJARs = true; 051 052 protected boolean scanForNestedJARs = true; 053 054 public ApplicationBundleLoader(StandaloneApplication app) { 055 this(app, false); 056 } 057 058 public ApplicationBundleLoader(StandaloneApplication app, boolean useCache) { 059 this.app = app; 060 bundleLoader = new StandaloneBundleLoader(app); 061 this.useCache = useCache; 062 } 063 064 public void setScanForNestedJARs(boolean scanForNestedJARs) { 065 this.scanForNestedJARs = scanForNestedJARs; 066 } 067 068 public boolean getScanForNestedJARs() { 069 return scanForNestedJARs; 070 } 071 072 public void setExtractNestedJARs(boolean extractNestedJARs) { 073 this.extractNestedJARs = extractNestedJARs; 074 } 075 076 public boolean getExtractNestedJARs() { 077 return extractNestedJARs; 078 } 079 080 public void setUseCache(boolean useCache) { 081 this.useCache = useCache; 082 } 083 084 public boolean getUseCache() { 085 return useCache; 086 } 087 088 public StandaloneBundleLoader getBundleLoader() { 089 return bundleLoader; 090 } 091 092 public File getCacheFile() { 093 return new File(app.getDataDir(), "bundles.cache"); 094 } 095 096 public ClassLoader loadBundles(List<File> classPath) throws IOException, BundleException { 097 // create the standalone loader 098 bundleLoader = new StandaloneBundleLoader(app, app.getSharedClassLoader()); 099 Thread.currentThread().setContextClassLoader(bundleLoader.getSharedClassLoader().getLoader()); 100 101 aboutToStartRuntime(); 102 boolean scan = true; 103 File file = getCacheFile(); 104 if (useCache) { 105 if (file.isFile()) { // use the cache 106 scan = false; 107 try { 108 fastLoad(file); 109 } catch (IOException e) { 110 scan = true; 111 } catch (BundleException e) { 112 scan = true; 113 } 114 } 115 } 116 if (scan) { 117 List<BundleFile> bundles = new ArrayList<BundleFile>(); 118 List<BundleFile> jars = new ArrayList<BundleFile>(); 119 scanAndLoad(classPath, bundles, jars); 120 writeCache(file, bundles, jars); 121 app.installAll(bundles); 122 } 123 // that's all 124 runtimeStarted(); 125 return bundleLoader.getSharedClassLoader().getLoader(); 126 } 127 128 public void scanAndLoad(List<File> classPath, List<BundleFile> bundles, List<BundleFile> jars) { 129 bundleLoader.setScanForNestedJARs(scanForNestedJARs); 130 bundleLoader.setExtractNestedJARs(extractNestedJARs); 131 132 for (File file : classPath) { 133 if (file.isFile()) { // a JAR file 134 String name = file.getName(); 135 if (!name.endsWith(".jar") || name.endsWith(".rar") || name.endsWith(".zip") || name.endsWith(".sar")) { 136 continue; 137 } 138 try { 139 JarFile jar = new JarFile(file); 140 JarBundleFile bf = new JarBundleFile(jar); 141 if (bf.getSymbolicName() != null) { 142 bundles.add(bf); 143 } else { 144 jars.add(bf); 145 } 146 } catch (IOException e) { // may be not a JAR 147 continue; 148 } 149 } else if (file.isDirectory()) { // a file directory 150 try { 151 DirectoryBundleFile bf = new DirectoryBundleFile(file); 152 if (bf.getSymbolicName() != null) { 153 bundles.add(bf); 154 } else { 155 jars.add(bf); 156 } 157 } catch (IOException e) { 158 continue; 159 } 160 } 161 } 162 } 163 164 public static void writeCache(File file, List<BundleFile> bundles, List<BundleFile> jars) throws IOException { 165 // write loaded bundles to the cache 166 BufferedWriter writer = null; 167 try { 168 writer = new BufferedWriter(new FileWriter(file)); 169 for (BundleFile bf : bundles) { 170 writer.append(bf.getFile().getAbsolutePath()); 171 writer.newLine(); 172 } 173 writer.append("#"); 174 writer.newLine(); 175 for (BundleFile bf : jars) { 176 writer.append(bf.getFile().getAbsolutePath()); 177 writer.newLine(); 178 } 179 } finally { 180 if (writer != null) { 181 writer.close(); 182 } 183 } 184 } 185 186 public void fastLoad(File file) throws IOException, BundleException { 187 BufferedReader reader = null; 188 List<BundleFile> bundles = new ArrayList<BundleFile>(); 189 try { 190 reader = new BufferedReader(new FileReader(file)); 191 List<BundleFile> list = bundles; 192 while (true) { 193 String line = reader.readLine(); 194 if (line == null) { 195 break; 196 } 197 if (line.startsWith("#")) { 198 list = null; 199 continue; 200 } 201 BundleFile bf = null; 202 File f = new File(line.trim()); 203 if (f.isDirectory()) { 204 bf = new DirectoryBundleFile(f); 205 } else { 206 bf = new JarBundleFile(f); 207 } 208 bundleLoader.loadJAR(bf); 209 if (list != null) { 210 list.add(bf); 211 } 212 } 213 } finally { 214 if (reader != null) { 215 reader.close(); 216 } 217 } 218 // install found bundles 219 app.installAll(bundles); 220 } 221 222 protected void aboutToStartRuntime() { 223 // do nothing 224 } 225 226 protected void runtimeStarted() { 227 // do nothing 228 } 229 230}