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; 023 024import java.io.File; 025import java.net.URL; 026import java.util.Dictionary; 027import java.util.Hashtable; 028import java.util.jar.Attributes; 029import java.util.jar.Manifest; 030import java.util.regex.Matcher; 031import java.util.regex.Pattern; 032 033import org.apache.commons.logging.Log; 034import org.apache.commons.logging.LogFactory; 035import org.nuxeo.common.utils.JarUtils; 036import org.nuxeo.common.utils.StringUtils; 037import org.osgi.framework.BundleException; 038import org.osgi.framework.Constants; 039 040/** 041 * @author <a href="mailto:[email protected]">Bogdan Stefanescu</a> 042 */ 043public final class BundleManifestReader { 044 045 private static final Log log = LogFactory.getLog(BundleManifestReader.class); 046 047 private static final Pattern PARAMS_PATTERN = Pattern.compile("\\s*([^:\\s]+)\\s*:=\\s*([^;\\s]+)\\s*;?"); 048 049 public static final String COMPONENT_HEADER = "Nuxeo-Component"; 050 051 public static final String ALLOW_HOST_OVERRIDE = "Nuxeo-AllowOverride"; 052 053 public static final String WEB_MODULE = "Nuxeo-WebModule"; 054 055 protected static final String[] CUSTOM_HEADERS; 056 057 static { // we can add dynamically new headers through system properties 058 String h = System.getProperty("org.nuxeo.manifest.headers"); 059 if (h != null) { 060 CUSTOM_HEADERS = StringUtils.split(h, ',', true); 061 } else { 062 CUSTOM_HEADERS = new String[] { COMPONENT_HEADER, WEB_MODULE, ALLOW_HOST_OVERRIDE }; 063 } 064 } 065 066 // Utility class 067 private BundleManifestReader() { 068 } 069 070 public static Dictionary<String, String> getHeadersFromJar(URL url) { 071 Manifest mf = JarUtils.getManifest(url); 072 if (mf != null) { 073 try { 074 return getHeaders(mf); 075 } catch (BundleException e) { 076 log.error(e, e); 077 } 078 } 079 // not an osgi bundle 080 return getDefaultHeaders(url.toExternalForm()); 081 } 082 083 public static Dictionary<String, String> getHeadersFromFile(File file) { 084 Manifest mf = JarUtils.getManifest(file); 085 if (mf != null) { 086 try { 087 return getHeaders(mf); 088 } catch (BundleException e) { 089 log.error(e, e); 090 } 091 } 092 // not an osgi bundle 093 return getDefaultHeaders(file.getAbsolutePath()); 094 } 095 096 public static Dictionary<String, String> getDefaultHeaders(String symbolicName) { 097 Dictionary<String, String> headers = new Hashtable<String, String>(); 098 headers.put(Constants.BUNDLE_SYMBOLICNAME, symbolicName); 099 headers.put(Constants.BUNDLE_ACTIVATOR, NullActivator.class.getName()); 100 return headers; 101 } 102 103 public static Dictionary<String, String> getHeaders(Manifest mf) throws BundleException { 104 Attributes attrs = mf.getMainAttributes(); 105 String symbolicName = attrs.getValue(Constants.BUNDLE_SYMBOLICNAME); 106 if (symbolicName == null) { 107 throw new BundleException("Missing " + Constants.BUNDLE_SYMBOLICNAME); 108 } 109 Hashtable<String, String> headers = new Hashtable<String, String>(); 110 parseSymbolicName(headers, symbolicName); 111 String val = attrs.getValue(Constants.BUNDLE_ACTIVATOR); 112 if (val != null) { 113 headers.put(Constants.BUNDLE_ACTIVATOR, val.trim()); 114 } 115 val = attrs.getValue(Constants.BUNDLE_CLASSPATH); 116 if (val != null) { 117 headers.put(Constants.BUNDLE_CLASSPATH, val.trim()); 118 } 119 val = attrs.getValue(Constants.BUNDLE_NAME); 120 if (val != null) { 121 headers.put(Constants.BUNDLE_NAME, val); 122 } 123 val = attrs.getValue(Constants.BUNDLE_VENDOR); 124 if (val != null) { 125 headers.put(Constants.BUNDLE_VENDOR, val); 126 } 127 val = attrs.getValue(Constants.BUNDLE_VERSION); 128 if (val != null) { 129 headers.put(Constants.BUNDLE_VERSION, val); 130 } 131 val = attrs.getValue(Constants.BUNDLE_DESCRIPTION); 132 if (val != null) { 133 headers.put(Constants.BUNDLE_DESCRIPTION, val); 134 } 135 val = attrs.getValue(Constants.BUNDLE_DOCURL); 136 if (val != null) { 137 headers.put(Constants.BUNDLE_DOCURL, val); 138 } 139 val = attrs.getValue(Constants.BUNDLE_COPYRIGHT); 140 if (val != null) { 141 headers.put(Constants.BUNDLE_COPYRIGHT, val); 142 } 143 val = attrs.getValue(Constants.BUNDLE_LOCALIZATION); 144 if (val != null) { 145 headers.put(Constants.BUNDLE_LOCALIZATION, val); 146 } 147 val = attrs.getValue(Constants.REQUIRE_BUNDLE); 148 if (val != null) { 149 headers.put(Constants.REQUIRE_BUNDLE, val); 150 } 151 val = attrs.getValue(Constants.FRAGMENT_HOST); 152 if (val != null) { 153 headers.put(Constants.FRAGMENT_HOST, val); 154 } 155 // Nuxeo headers 156 for (String key : CUSTOM_HEADERS) { 157 val = attrs.getValue(key); 158 if (val != null) { 159 headers.put(key, val); 160 } 161 } 162 return headers; 163 } 164 165 private static void parseSymbolicName(Dictionary<String, String> headers, String name) { 166 int p = name.indexOf(';'); 167 if (p > 0) { 168 headers.put(Constants.BUNDLE_SYMBOLICNAME, name.substring(0, p).trim()); 169 String tail = name.substring(p + 1); 170 Matcher m = PARAMS_PATTERN.matcher(tail); 171 while (m.find()) { 172 headers.put(m.group(1), m.group(2)); 173 } 174 } else { 175 headers.put(Constants.BUNDLE_SYMBOLICNAME, name.trim()); 176 } 177 } 178 179 public static String removePropertiesFromHeaderValue(String value) { 180 int p = value.indexOf(';'); 181 if (p > 0) { 182 return value.substring(0, p).trim(); 183 } else { 184 return value; 185 } 186 } 187 188}