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; 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:bs@nuxeo.com">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 public static String[] CUSTOM_HEADERS = { COMPONENT_HEADER, WEB_MODULE, ALLOW_HOST_OVERRIDE }; 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 } 062 } 063 064 // Utility class 065 private BundleManifestReader() { 066 } 067 068 public static Dictionary<String, String> getHeadersFromJar(URL url) { 069 Manifest mf = JarUtils.getManifest(url); 070 if (mf != null) { 071 try { 072 return getHeaders(mf); 073 } catch (BundleException e) { 074 log.error(e, e); 075 } 076 } 077 // not an osgi bundle 078 return getDefaultHeaders(url.toExternalForm()); 079 } 080 081 public static Dictionary<String, String> getHeadersFromFile(File file) { 082 Manifest mf = JarUtils.getManifest(file); 083 if (mf != null) { 084 try { 085 return getHeaders(mf); 086 } catch (BundleException e) { 087 log.error(e, e); 088 } 089 } 090 // not an osgi bundle 091 return getDefaultHeaders(file.getAbsolutePath()); 092 } 093 094 public static Dictionary<String, String> getDefaultHeaders(String symbolicName) { 095 Dictionary<String, String> headers = new Hashtable<String, String>(); 096 headers.put(Constants.BUNDLE_SYMBOLICNAME, symbolicName); 097 headers.put(Constants.BUNDLE_ACTIVATOR, NullActivator.class.getName()); 098 return headers; 099 } 100 101 public static Dictionary<String, String> getHeaders(Manifest mf) throws BundleException { 102 Attributes attrs = mf.getMainAttributes(); 103 String symbolicName = attrs.getValue(Constants.BUNDLE_SYMBOLICNAME); 104 if (symbolicName == null) { 105 throw new BundleException("Missing " + Constants.BUNDLE_SYMBOLICNAME); 106 } 107 Hashtable<String, String> headers = new Hashtable<String, String>(); 108 parseSymbolicName(headers, symbolicName); 109 String val = attrs.getValue(Constants.BUNDLE_ACTIVATOR); 110 if (val != null) { 111 headers.put(Constants.BUNDLE_ACTIVATOR, val.trim()); 112 } 113 val = attrs.getValue(Constants.BUNDLE_CLASSPATH); 114 if (val != null) { 115 headers.put(Constants.BUNDLE_CLASSPATH, val.trim()); 116 } 117 val = attrs.getValue(Constants.BUNDLE_NAME); 118 if (val != null) { 119 headers.put(Constants.BUNDLE_NAME, val); 120 } 121 val = attrs.getValue(Constants.BUNDLE_VENDOR); 122 if (val != null) { 123 headers.put(Constants.BUNDLE_VENDOR, val); 124 } 125 val = attrs.getValue(Constants.BUNDLE_VERSION); 126 if (val != null) { 127 headers.put(Constants.BUNDLE_VERSION, val); 128 } 129 val = attrs.getValue(Constants.BUNDLE_DESCRIPTION); 130 if (val != null) { 131 headers.put(Constants.BUNDLE_DESCRIPTION, val); 132 } 133 val = attrs.getValue(Constants.BUNDLE_DOCURL); 134 if (val != null) { 135 headers.put(Constants.BUNDLE_DOCURL, val); 136 } 137 val = attrs.getValue(Constants.BUNDLE_COPYRIGHT); 138 if (val != null) { 139 headers.put(Constants.BUNDLE_COPYRIGHT, val); 140 } 141 val = attrs.getValue(Constants.BUNDLE_LOCALIZATION); 142 if (val != null) { 143 headers.put(Constants.BUNDLE_LOCALIZATION, val); 144 } 145 val = attrs.getValue(Constants.REQUIRE_BUNDLE); 146 if (val != null) { 147 headers.put(Constants.REQUIRE_BUNDLE, val); 148 } 149 val = attrs.getValue(Constants.FRAGMENT_HOST); 150 if (val != null) { 151 headers.put(Constants.FRAGMENT_HOST, val); 152 } 153 // Nuxeo headers 154 for (String key : CUSTOM_HEADERS) { 155 val = attrs.getValue(key); 156 if (val != null) { 157 headers.put(key, val); 158 } 159 } 160 return headers; 161 } 162 163 private static void parseSymbolicName(Dictionary<String, String> headers, String name) { 164 int p = name.indexOf(';'); 165 if (p > 0) { 166 headers.put(Constants.BUNDLE_SYMBOLICNAME, name.substring(0, p).trim()); 167 String tail = name.substring(p + 1); 168 Matcher m = PARAMS_PATTERN.matcher(tail); 169 while (m.find()) { 170 headers.put(m.group(1), m.group(2)); 171 } 172 } else { 173 headers.put(Constants.BUNDLE_SYMBOLICNAME, name.trim()); 174 } 175 } 176 177 public static String removePropertiesFromHeaderValue(String value) { 178 int p = value.indexOf(';'); 179 if (p > 0) { 180 return value.substring(0, p).trim(); 181 } else { 182 return value; 183 } 184 } 185 186}