/** * Copyright (c) 2015, Lucee Assosication Switzerland. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. * */ package lucee.runtime.osgi; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; import lucee.commons.io.IOUtil; import lucee.commons.io.res.Resource; import lucee.commons.io.res.type.file.FileResource; import lucee.commons.lang.ExceptionUtil; import lucee.commons.lang.StringUtil; import lucee.runtime.op.Caster; import lucee.runtime.osgi.OSGiUtil.BundleDefinition; import lucee.runtime.type.Struct; import lucee.runtime.type.StructImpl; import lucee.runtime.type.util.KeyConstants; import org.osgi.framework.BundleException; import org.osgi.framework.Version; public class BundleInfo implements Serializable { private static final long serialVersionUID = -8723070772449992030L; private final Version version; private final String name; private final String symbolicName; private final String exportPackage; private final String importPackage; private final String activator; private final int manifestVersion; private final String description; private final String dynamicImportPackage; private final String classPath; private final String requireBundle; private final String fragementHost; private final Map<String, Object> headers; private final static Map<String, BundleInfo> bundles=new HashMap<String, BundleInfo>(); public static BundleInfo getInstance(String id, InputStream is, boolean closeStream) throws IOException, BundleException { BundleInfo bi = bundles.get(id); if(bi!=null) return bi; File tmp = File.createTempFile("temp-extension", "lex"); try { IOUtil.copy(is, new FileOutputStream(tmp), closeStream,true); bundles.put(id, bi = new BundleInfo(tmp)); return bi; } finally { tmp.delete(); } } public BundleInfo(Resource file) throws IOException, BundleException { this(toFileResource(file)); } public BundleInfo(File file) throws IOException, BundleException { JarFile jar=new JarFile(file); try { Manifest manifest = jar.getManifest(); Attributes attrs = manifest.getMainAttributes(); manifestVersion = Caster.toIntValue(attrs.getValue("Bundle-ManifestVersion"),1); name = attrs.getValue("Bundle-Name"); symbolicName = attrs.getValue("Bundle-SymbolicName"); String tmp = attrs.getValue("Bundle-Version"); version=StringUtil.isEmpty(tmp,true)?null:OSGiUtil.toVersion(tmp); exportPackage = attrs.getValue("Export-Package"); importPackage = attrs.getValue("Import-Package"); dynamicImportPackage = attrs.getValue("DynamicImport-Package"); activator = attrs.getValue("Bundle-Activator"); description = attrs.getValue("Bundle-Description"); classPath = attrs.getValue("Bundle-ClassPath"); requireBundle = attrs.getValue("Require-Bundle"); fragementHost = attrs.getValue("Fragment-Host"); headers=createHeaders(attrs); } finally { IOUtil.closeEL(jar); } } public boolean isBundle() { try { return getSymbolicName()!=null && getVersion()!=null; } catch(Throwable t) { ExceptionUtil.rethrowIfNecessary(t); return false; } } public String getRequireBundle() { return requireBundle; } public Version getVersion(){ return version; } public String getVersionAsString(){ return version==null?null:version.toString(); } private String getBundleName() { return name; } public String getSymbolicName() { return symbolicName; } public String getExportPackage() { return exportPackage; } public String getImportPackage() { return importPackage; } public String getActivator() { return activator; } public int getManifestVersion() { return manifestVersion; } public String getDescription() { return description; } public String getDynamicImportPackage() { return dynamicImportPackage; } public String getFragementHost() { return fragementHost; } public String getClassPath() { return classPath; } public Object info() { Struct sct=new StructImpl(); sct.setEL(KeyConstants._Name, getBundleName()); sct.setEL("Fragment-Host", getFragementHost()); sct.setEL("Activator", getActivator()); sct.setEL("ClassPath", getClassPath()); sct.setEL("Description", getDescription()); sct.setEL("DynamicImportPackage", getDynamicImportPackage()); sct.setEL("ExportPackage", getExportPackage()); sct.setEL("ImportPackage", getImportPackage()); sct.setEL("SymbolicName", getSymbolicName()); sct.setEL(KeyConstants._Version, getVersionAsString()); sct.setEL("ManifestVersion", getManifestVersion()); sct.setEL("RequireBundle", getRequireBundle()); return sct; } /** * Value can be a string (for a Single entry or a List<String> for multiple entries) * @return */ public Map<String, Object> getHeaders() { return headers; } private Map<String, Object> createHeaders(Attributes attrs) { Map<String, Object> headers=new HashMap<String, Object>(); Iterator<Entry<Object, Object>> it = attrs.entrySet().iterator(); Entry<Object, Object> e; String key,value; Object existing; List<String> list; while(it.hasNext()){ e = it.next(); key=e.getKey().toString(); value=StringUtil.unwrap(e.getValue().toString()); existing = headers.get(key); if(existing!=null) { if(existing instanceof String) { list=new ArrayList<>(); list.add((String)existing); headers.put(key, list); } else list=(List<String>) existing; list.add(value); } else headers.put(key, value); } return headers; } public BundleDefinition toBundleDefinition() { return new BundleDefinition(getSymbolicName(), getVersion()); } protected static File toFileResource(Resource file) throws IOException { if(file instanceof FileResource) return (File)file; throw new IOException("only file resources (local file system) are supported"); } }