/* * Copyright 2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.gradle.api.internal.plugins.osgi; import aQute.bnd.osgi.Analyzer; import org.gradle.api.file.FileCollection; import org.gradle.api.internal.file.FileResolver; import org.gradle.api.java.archives.Attributes; import org.gradle.api.java.archives.internal.DefaultManifest; import org.gradle.api.plugins.osgi.OsgiManifest; import org.gradle.api.specs.Spec; import org.gradle.internal.Factory; import org.gradle.internal.UncheckedException; import org.gradle.util.CollectionUtils; import org.gradle.util.WrapUtil; import java.io.File; import java.io.IOException; import java.util.*; import java.util.jar.Manifest; public class DefaultOsgiManifest extends DefaultManifest implements OsgiManifest { // Because these properties can be convention mapped we need special handling in here. // If you add another one of these “modelled” properties, you need to update: // - maybeAppendModelledInstruction() // - maybePrependModelledInstruction() // - maybeSetModelledInstruction() // - getModelledInstructions() // - instructionValue() private String symbolicName; private String name; private String version; private String description; private String license; private String vendor; private String docURL; private File classesDir; private Factory<ContainedVersionAnalyzer> analyzerFactory = new DefaultAnalyzerFactory(); private Map<String, List<String>> unmodelledInstructions = new HashMap<String, List<String>>(); private FileCollection classpath; public DefaultOsgiManifest(FileResolver fileResolver) { super(fileResolver); } @Override public DefaultManifest getEffectiveManifest() { ContainedVersionAnalyzer analyzer = analyzerFactory.create(); DefaultManifest effectiveManifest = new DefaultManifest(null); try { setAnalyzerProperties(analyzer); Manifest osgiManifest = analyzer.calcManifest(); java.util.jar.Attributes attributes = osgiManifest.getMainAttributes(); for (Map.Entry<Object, Object> entry : attributes.entrySet()) { effectiveManifest.attributes(WrapUtil.toMap(entry.getKey().toString(), (String) entry.getValue())); } effectiveManifest.attributes(this.getAttributes()); for (Map.Entry<String, Attributes> ent : getSections().entrySet()) { effectiveManifest.attributes(ent.getValue(), ent.getKey()); } if (classesDir != null) { long mod = classesDir.lastModified(); if (mod > 0) { effectiveManifest.getAttributes().put(Analyzer.BND_LASTMODIFIED, mod); } } } catch (Exception e) { throw UncheckedException.throwAsUncheckedException(e); } return getEffectiveManifestInternal(effectiveManifest); } private void setAnalyzerProperties(Analyzer analyzer) throws IOException { for (Map.Entry<String, Object> attribute : getAttributes().entrySet()) { String key = attribute.getKey(); if (!"Manifest-Version".equals(key)) { analyzer.setProperty(key, attribute.getValue().toString()); } } Map<String, List<String>> instructions = getInstructions(); Set<String> instructionNames = instructions.keySet(); if (!instructionNames.contains(Analyzer.IMPORT_PACKAGE)) { analyzer.setProperty(Analyzer.IMPORT_PACKAGE, "*, !org.apache.ant.*, !org.junit.*, !org.jmock.*, !org.easymock.*, !org.mockito.*"); } if(!instructionNames.contains(Analyzer.BUNDLE_VERSION)){ analyzer.setProperty(Analyzer.BUNDLE_VERSION, getVersion()); } if(!instructionNames.contains(Analyzer.BUNDLE_NAME)){ analyzer.setProperty(Analyzer.BUNDLE_NAME, getName()); } if(!instructionNames.contains(Analyzer.BUNDLE_SYMBOLICNAME)){ analyzer.setProperty(Analyzer.BUNDLE_SYMBOLICNAME, getSymbolicName()); } if (!instructionNames.contains(Analyzer.EXPORT_PACKAGE)) { analyzer.setProperty(Analyzer.EXPORT_PACKAGE, "*;-noimport:=false;version=" + getVersion()); } for (String instructionName : instructionNames) { String list = createPropertyStringFromList(instructionValue(instructionName)); if (list != null && list.length() > 0) { analyzer.setProperty(instructionName, list); } } analyzer.setJar(getClassesDir()); analyzer.setClasspath(getClasspath().getFiles().toArray(new File[0])); } public List<String> instructionValue(String instructionName) { if (instructionName.equals(Analyzer.BUNDLE_SYMBOLICNAME)) { return createListFromPropertyString(getSymbolicName()); } else if (instructionName.equals(Analyzer.BUNDLE_NAME)) { return createListFromPropertyString(getName()); } else if (instructionName.equals(Analyzer.BUNDLE_VERSION)) { return createListFromPropertyString(getVersion()); } else if (instructionName.equals(Analyzer.BUNDLE_DESCRIPTION)) { return createListFromPropertyString(getDescription()); } else if (instructionName.equals(Analyzer.BUNDLE_LICENSE)) { return createListFromPropertyString(getLicense()); } else if (instructionName.equals(Analyzer.BUNDLE_VENDOR)) { return createListFromPropertyString(getVendor()); } else if (instructionName.equals(Analyzer.BUNDLE_DOCURL)) { return createListFromPropertyString(getDocURL()); } else { return unmodelledInstructions.get(instructionName); } } public OsgiManifest instruction(String name, String... values) { if (!maybeAppendModelledInstruction(name, values)) { if (unmodelledInstructions.get(name) == null) { unmodelledInstructions.put(name, new ArrayList<String>()); } unmodelledInstructions.get(name).addAll(Arrays.asList(values)); } return this; } private String appendValues(String existingValues, String... toPrepend) { List<String> parts = createListFromPropertyString(existingValues); if (parts == null) { return createPropertyStringFromArray(toPrepend); } else { parts.addAll(Arrays.asList(toPrepend)); return createPropertyStringFromList(parts); } } private boolean maybeAppendModelledInstruction(String name, String... values) { if (name.equals(Analyzer.BUNDLE_SYMBOLICNAME)) { setSymbolicName(appendValues(getSymbolicName(), values)); return true; } else if (name.equals(Analyzer.BUNDLE_NAME)) { setName(appendValues(getName(), values)); return true; } else if (name.equals(Analyzer.BUNDLE_VERSION)) { setVersion(appendValues(getVersion(), values)); return true; } else if (name.equals(Analyzer.BUNDLE_DESCRIPTION)) { setDescription(appendValues(getDescription(), values)); return true; } else if (name.equals(Analyzer.BUNDLE_LICENSE)) { setLicense(appendValues(getLicense(), values)); return true; } else if (name.equals(Analyzer.BUNDLE_VENDOR)) { setVendor(appendValues(getVendor(), values)); return true; } else if (name.equals(Analyzer.BUNDLE_DOCURL)) { setDocURL(appendValues(getDocURL(), values)); return true; } else { return false; } } public OsgiManifest instructionFirst(String name, String... values) { if (!maybePrependModelledInstruction(name, values)) { if (unmodelledInstructions.get(name) == null) { unmodelledInstructions.put(name, new ArrayList<String>()); } unmodelledInstructions.get(name).addAll(0, Arrays.asList(values)); } return this; } private String prependValues(String existingValues, String... toPrepend) { List<String> parts = createListFromPropertyString(existingValues); if (parts == null) { return createPropertyStringFromArray(toPrepend); } else { parts.addAll(0, Arrays.asList(toPrepend)); return createPropertyStringFromList(parts); } } private boolean maybePrependModelledInstruction(String name, String... values) { if (name.equals(Analyzer.BUNDLE_SYMBOLICNAME)) { setSymbolicName(prependValues(getSymbolicName(), values)); return true; } else if (name.equals(Analyzer.BUNDLE_NAME)) { setName(prependValues(getName(), values)); return true; } else if (name.equals(Analyzer.BUNDLE_VERSION)) { setVersion(prependValues(getVersion(), values)); return true; } else if (name.equals(Analyzer.BUNDLE_DESCRIPTION)) { setDescription(prependValues(getDescription(), values)); return true; } else if (name.equals(Analyzer.BUNDLE_LICENSE)) { setLicense(prependValues(getLicense(), values)); return true; } else if (name.equals(Analyzer.BUNDLE_VENDOR)) { setVendor(prependValues(getVendor(), values)); return true; } else if (name.equals(Analyzer.BUNDLE_DOCURL)) { setDocURL(prependValues(getDocURL(), values)); return true; } else { return false; } } public OsgiManifest instructionReplace(String name, String... values) { if (!maybeSetModelledInstruction(name, values)) { if (values.length == 0 || (values.length == 1 && values[0] == null)) { unmodelledInstructions.remove(name); } else { if (unmodelledInstructions.get(name) == null) { unmodelledInstructions.put(name, new ArrayList<String>()); } List<String> instructionsForName = unmodelledInstructions.get(name); instructionsForName.clear(); Collections.addAll(instructionsForName, values); } } return this; } private boolean maybeSetModelledInstruction(String name, String... values) { if (name.equals(Analyzer.BUNDLE_SYMBOLICNAME)) { setSymbolicName(createPropertyStringFromArray(values)); return true; } else if (name.equals(Analyzer.BUNDLE_NAME)) { setName(createPropertyStringFromArray(values)); return true; } else if (name.equals(Analyzer.BUNDLE_VERSION)) { setVersion(createPropertyStringFromArray(values)); return true; } else if (name.equals(Analyzer.BUNDLE_DESCRIPTION)) { setDescription(createPropertyStringFromArray(values)); return true; } else if (name.equals(Analyzer.BUNDLE_LICENSE)) { setLicense(createPropertyStringFromArray(values)); return true; } else if (name.equals(Analyzer.BUNDLE_VENDOR)) { setVendor(createPropertyStringFromArray(values)); return true; } else if (name.equals(Analyzer.BUNDLE_DOCURL)) { setDocURL(createPropertyStringFromArray(values)); return true; } else { return false; } } public Map<String, List<String>> getInstructions() { Map<String, List<String>> instructions = new HashMap<String, List<String>>(); instructions.putAll(unmodelledInstructions); instructions.putAll(getModelledInstructions()); return instructions; } private String createPropertyStringFromArray(String... valueList) { return createPropertyStringFromList(Arrays.asList(valueList)); } private String createPropertyStringFromList(List<String> valueList) { return valueList == null || valueList.isEmpty() ? null : CollectionUtils.join(",", valueList); } private List<String> createListFromPropertyString(String propertyString) { return propertyString == null || propertyString.length() == 0 ? null : new LinkedList<String>(Arrays.asList(propertyString.split(","))); } private Map<String, List<String>> getModelledInstructions() { Map<String, List<String>> modelledInstructions = new HashMap<String, List<String>>(); modelledInstructions.put(Analyzer.BUNDLE_SYMBOLICNAME, createListFromPropertyString(symbolicName)); modelledInstructions.put(Analyzer.BUNDLE_NAME, createListFromPropertyString(name)); modelledInstructions.put(Analyzer.BUNDLE_VERSION, createListFromPropertyString(version)); modelledInstructions.put(Analyzer.BUNDLE_DESCRIPTION, createListFromPropertyString(description)); modelledInstructions.put(Analyzer.BUNDLE_LICENSE, createListFromPropertyString(license)); modelledInstructions.put(Analyzer.BUNDLE_VENDOR, createListFromPropertyString(vendor)); modelledInstructions.put(Analyzer.BUNDLE_DOCURL, createListFromPropertyString(docURL)); return CollectionUtils.filter(modelledInstructions, new Spec<Map.Entry<String, List<String>>>() { public boolean isSatisfiedBy(Map.Entry<String, List<String>> element) { return element.getValue() != null; } }); } public String getSymbolicName() { return symbolicName; } public void setSymbolicName(String symbolicName) { this.symbolicName = symbolicName; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getLicense() { return license; } public void setLicense(String license) { this.license = license; } public String getVendor() { return vendor; } public void setVendor(String vendor) { this.vendor = vendor; } public String getDocURL() { return docURL; } public void setDocURL(String docURL) { this.docURL = docURL; } public File getClassesDir() { return classesDir; } public void setClassesDir(File classesDir) { this.classesDir = classesDir; } public FileCollection getClasspath() { return classpath; } public void setClasspath(FileCollection classpath) { this.classpath = classpath; } public Factory<ContainedVersionAnalyzer> getAnalyzerFactory() { return analyzerFactory; } public void setAnalyzerFactory(Factory<ContainedVersionAnalyzer> analyzerFactory) { this.analyzerFactory = analyzerFactory; } }