001/* 002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and contributors. 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.jar.JarFile; 028import java.util.jar.Manifest; 029 030import org.apache.commons.logging.Log; 031import org.apache.commons.logging.LogFactory; 032import org.nuxeo.common.utils.FileNamePattern; 033import org.nuxeo.common.utils.JarUtils; 034import org.nuxeo.osgi.BundleFile; 035import org.nuxeo.osgi.DirectoryBundleFile; 036import org.nuxeo.osgi.JarBundleFile; 037import org.osgi.framework.BundleException; 038import org.osgi.framework.Constants; 039 040/** 041 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 042 */ 043public class BundleWalker extends FileWalker.Visitor { 044 045 private static final Log log = LogFactory.getLog(BundleWalker.class); 046 047 public static final FileNamePattern[] DEFAULT_PATTERNS = { new FileNamePattern("*.jar"), 048 new FileNamePattern("*.war"), new FileNamePattern("*.rar"), new FileNamePattern("*.sar"), // jboss sar 049 new FileNamePattern("*_jar"), new FileNamePattern("*_war"), new FileNamePattern("*_rar") }; 050 051 private FileNamePattern[] patterns; 052 053 private final Callback callback; 054 055 public BundleWalker(Callback cb) { 056 this(cb, DEFAULT_PATTERNS); 057 } 058 059 public BundleWalker(Callback cb, String[] patterns) { 060 if (patterns != null) { 061 this.patterns = new FileNamePattern[patterns.length]; 062 for (int i = 0; i < patterns.length; i++) { 063 this.patterns[i] = new FileNamePattern(patterns[i]); 064 } 065 } 066 callback = cb; 067 } 068 069 public BundleWalker(Callback cb, FileNamePattern[] patterns) { 070 this.patterns = patterns; 071 callback = cb; 072 } 073 074 public void visit(File root) { 075 new FileWalker().walk(root, this); 076 } 077 078 public void visit(Collection<File> files) { 079 for (File file : files) { 080 if (file.isFile()) { 081 if (file.isFile()) { 082 visitFile(file); 083 } else if (file.isDirectory()) { 084 visitDirectory(file); 085 } 086 } 087 } 088 } 089 090 public void visit(File... files) { 091 for (File file : files) { 092 if (file.isFile()) { 093 if (file.isFile()) { 094 visitFile(file); 095 } else if (file.isDirectory()) { 096 visitDirectory(file); 097 } 098 } 099 } 100 } 101 102 @Override 103 public int visitDirectory(File file) { 104 // System.out.println("###### Processing DIR: " + file); 105 // first check if this is a possible bundle 106 String fileName = file.getName(); 107 if (patterns != null) { 108 if (!acceptFile(fileName, patterns)) { 109 return FileWalker.CONTINUE; 110 } 111 } 112 // check if this is an OSGi bundle 113 try { 114 Manifest mf = JarUtils.getDirectoryManifest(file); 115 if (mf == null) { 116 return FileWalker.CONTINUE; 117 } 118 String bundleName = mf.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME); 119 if (bundleName != null) { 120 // notify the callback about the new bundle 121 callback.visitBundle(new DirectoryBundleFile(file, mf)); 122 // assume that a directory OSGi bundle cannot contain other bundles so skip it 123 return FileWalker.BREAK; 124 } 125 } catch (IOException e) { 126 log.error(e, e); 127 } 128 return FileWalker.CONTINUE; 129 } 130 131 @Override 132 public int visitFile(File file) { 133 // System.out.println("###### Processing file: "+file); 134 // first check if this is a possible bundle 135 String fileName = file.getName(); 136 if (patterns != null) { 137 if (!acceptFile(fileName, patterns)) { 138 // System.out.println("###### Ignoring file based on name: "+file); 139 return FileWalker.CONTINUE; 140 } 141 } 142 // check if this is an OSGi bundle 143 try { 144 JarFile jarFile = new JarFile(file); 145 if (jarFile.getManifest() == null) { 146 // System.out.println("###### No manifest found: "+file); 147 return FileWalker.CONTINUE; 148 } 149 BundleFile bundleFile = new JarBundleFile(jarFile); 150 if (bundleFile.getSymbolicName() != null) { 151 // System.out.println("###### Bundle symbolic name: "+bundleFile.getSymbolicName()); 152 153 // notify the callback about the new bundle 154 callback.visitBundle(bundleFile); 155 } else { 156 // notify the callback about the new jar 157 callback.visitJar(bundleFile); 158 } 159 } catch (IOException e) { 160 // ignore 161 } 162 return FileWalker.CONTINUE; 163 } 164 165 protected boolean acceptFile(String fileName, FileNamePattern[] patterns) { 166 int i = 0; 167 for (; i < patterns.length; i++) { 168 if (patterns[i].match(fileName)) { 169 break; 170 } 171 } 172 return i < patterns.length; 173 } 174 175 public interface Callback { 176 void visitBundle(BundleFile bundleFile) throws IOException; 177 178 void visitJar(BundleFile bundleFile) throws IOException; 179 } 180 181}