blob: e23bb0665a9c6d5eb86637a4f8dc94c60071bdd3 [file] [log] [blame]
/*
* 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.apache.aries.subsystem.core.archive;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import org.apache.aries.subsystem.core.internal.OsgiIdentityCapability;
import org.apache.aries.util.manifest.ManifestProcessor;
import org.osgi.framework.Constants;
import org.osgi.framework.Version;
import org.osgi.resource.Capability;
import org.osgi.resource.Requirement;
import org.osgi.resource.Resource;
import org.osgi.service.subsystem.SubsystemConstants;
public class SubsystemManifest {
public static class Builder {
private Map<String, Header<?>> headers = new HashMap<String, Header<?>>();
public SubsystemManifest build() {
return new SubsystemManifest(headers);
}
public Builder content(String value) {
return value == null ? this : content(new SubsystemContentHeader(value));
}
public Builder content(Collection<Resource> value) {
return value == null || value.isEmpty() ? this : content(SubsystemContentHeader.newInstance(value));
}
public Builder content(SubsystemContentHeader value) {
return header(value);
}
public Builder header(Header<?> value) {
if (value != null)
headers.put(value.getName(), value);
return this;
}
public Builder manifest(SubsystemManifest value) {
for (Entry<String, Header<?>> entry : value.getHeaders().entrySet())
header(entry.getValue());
return this;
}
public Builder symbolicName(String value) {
return value == null ? this : symbolicName(new SubsystemSymbolicNameHeader(value));
}
public Builder symbolicName(SubsystemSymbolicNameHeader value) {
return header(value);
}
public Builder type(String value) {
return value == null ? this : type(new SubsystemTypeHeader(value));
}
public Builder type(SubsystemTypeHeader value) {
return header(value);
}
public Builder version(String value) {
return value == null ? this : version(Version.parseVersion(value));
}
public Builder version(Version value) {
return value == null ? this : version(new SubsystemVersionHeader(value));
}
public Builder version(SubsystemVersionHeader value) {
return header(value);
}
}
public static final String EXPORT_PACKAGE = Constants.EXPORT_PACKAGE;
public static final String IMPORT_PACKAGE = Constants.IMPORT_PACKAGE;
public static final String PREFERRED_PROVIDER = SubsystemConstants.PREFERRED_PROVIDER;
public static final String PROVIDE_CAPABILITY = Constants.PROVIDE_CAPABILITY;
public static final String REQUIRE_BUNDLE = Constants.REQUIRE_BUNDLE;
public static final String REQUIRE_CAPABILITY = Constants.REQUIRE_CAPABILITY;
public static final String SUBSYSTEM_CONTENT = SubsystemConstants.SUBSYSTEM_CONTENT;
public static final String SUBSYSTEM_DESCRIPTION = SubsystemConstants.SUBSYSTEM_DESCRIPTION;
public static final String SUBSYSTEM_EXPORTSERVICE = SubsystemConstants.SUBSYSTEM_EXPORTSERVICE;
public static final String SUBSYSTEM_IMPORTSERVICE = SubsystemConstants.SUBSYSTEM_IMPORTSERVICE;
public static final String SUBSYSTEM_MANIFESTVERSION = SubsystemConstants.SUBSYSTEM_MANIFESTVERSION;
public static final String SUBSYSTEM_NAME = SubsystemConstants.SUBSYSTEM_NAME;
public static final String SUBSYSTEM_SYMBOLICNAME = SubsystemConstants.SUBSYSTEM_SYMBOLICNAME;
public static final String SUBSYSTEM_TYPE = SubsystemConstants.SUBSYSTEM_TYPE;
public static final String SUBSYSTEM_VERSION = SubsystemConstants.SUBSYSTEM_VERSION;
private static Map<String, Header<?>> parseHeaders(java.util.jar.Manifest manifest) {
Map<String, Header<?>> result = new HashMap<String, Header<?>>();
for (Entry<Object, Object> entry : manifest.getMainAttributes().entrySet()) {
String key = String.valueOf(entry.getKey());
result.put(key, HeaderFactory.createHeader(key, String.valueOf(entry.getValue())));
}
return result;
}
private static void fillInDefaults(Map<String, Header<?>> headers) {
Header<?> header = headers.get(SUBSYSTEM_VERSION);
if (header == null) {
headers.put(SUBSYSTEM_VERSION, SubsystemVersionHeader.DEFAULT);
}
header = headers.get(SUBSYSTEM_TYPE);
if (header == null)
headers.put(SUBSYSTEM_TYPE, SubsystemTypeHeader.DEFAULT);
}
private final Map<String, Header<?>> headers;
private SubsystemManifest(Map<String, Header<?>> headers) {
Map<String, Header<?>> map = new HashMap<String, Header<?>>(headers);
fillInDefaults(map);
this.headers = Collections.unmodifiableMap(map);
}
public SubsystemManifest(java.util.jar.Manifest manifest) {
this(parseHeaders(manifest));
}
public SubsystemManifest(File file) throws FileNotFoundException, IOException {
this(new FileInputStream(file));
}
public SubsystemManifest(InputStream in) throws IOException {
Manifest manifest = ManifestProcessor.parseManifest(in);
Attributes attributes = manifest.getMainAttributes();
Map<String, Header<?>> headers = new HashMap<String, Header<?>>(attributes.size() + 4); // Plus the # of potentially derived headers.
for (Entry<Object, Object> entry : attributes.entrySet()) {
String key = String.valueOf(entry.getKey());
headers.put(key, HeaderFactory.createHeader(key, String.valueOf(entry.getValue())));
}
fillInDefaults(headers);
this.headers = Collections.unmodifiableMap(headers);
}
public SubsystemManifest(String symbolicName, Version version, Collection<Resource> content) {
this(null, symbolicName, version, content);
}
public SubsystemManifest(SubsystemManifest manifest, String symbolicName, Version version, Collection<Resource> content) {
Map<String, Header<?>> headers;
if (manifest == null) {
headers = new HashMap<String, Header<?>>(4);
}
else {
headers = new HashMap<String, Header<?>>(manifest.headers);
}
Header<?> header = headers.get(SUBSYSTEM_SYMBOLICNAME);
if (header == null)
headers.put(SUBSYSTEM_SYMBOLICNAME, new SubsystemSymbolicNameHeader(symbolicName));
header = headers.get(SUBSYSTEM_VERSION);
if (header == null && !(version == null)) {
headers.put(SUBSYSTEM_VERSION, new SubsystemVersionHeader(version));
}
header = headers.get(SUBSYSTEM_CONTENT);
if (header == null && content != null && !content.isEmpty()) {
headers.put(SubsystemContentHeader.NAME, SubsystemContentHeader.newInstance(content));
}
fillInDefaults(headers);
this.headers = Collections.unmodifiableMap(headers);
}
public Map<String, Header<?>> getHeaders() {
return headers;
}
public ExportPackageHeader getExportPackageHeader() {
return (ExportPackageHeader)getHeaders().get(EXPORT_PACKAGE);
}
public ImportPackageHeader getImportPackageHeader() {
return (ImportPackageHeader)getHeaders().get(IMPORT_PACKAGE);
}
public PreferredProviderHeader getPreferredProviderHeader() {
return (PreferredProviderHeader)getHeaders().get(PREFERRED_PROVIDER);
}
public ProvideCapabilityHeader getProvideCapabilityHeader() {
return (ProvideCapabilityHeader)getHeaders().get(PROVIDE_CAPABILITY);
}
public RequireBundleHeader getRequireBundleHeader() {
return (RequireBundleHeader)getHeaders().get(REQUIRE_BUNDLE);
}
public RequireCapabilityHeader getRequireCapabilityHeader() {
return (RequireCapabilityHeader)getHeaders().get(REQUIRE_CAPABILITY);
}
public SubsystemContentHeader getSubsystemContentHeader() {
return (SubsystemContentHeader)getHeaders().get(SUBSYSTEM_CONTENT);
}
public SubsystemExportServiceHeader getSubsystemExportServiceHeader() {
return (SubsystemExportServiceHeader)getHeaders().get(SUBSYSTEM_EXPORTSERVICE);
}
public SubsystemImportServiceHeader getSubsystemImportServiceHeader() {
return (SubsystemImportServiceHeader)getHeaders().get(SUBSYSTEM_IMPORTSERVICE);
}
public SubsystemSymbolicNameHeader getSubsystemSymbolicNameHeader() {
return (SubsystemSymbolicNameHeader)getHeaders().get(SUBSYSTEM_SYMBOLICNAME);
}
public SubsystemTypeHeader getSubsystemTypeHeader() {
return (SubsystemTypeHeader)getHeaders().get(SUBSYSTEM_TYPE);
}
public SubsystemVersionHeader getSubsystemVersionHeader() {
return (SubsystemVersionHeader)getHeaders().get(SUBSYSTEM_VERSION);
}
public List<Capability> toCapabilities(Resource resource) {
ArrayList<Capability> capabilities = new ArrayList<Capability>();
for (Header<?> header : headers.values())
if (header instanceof CapabilityHeader)
capabilities.addAll(((CapabilityHeader<?>)header).toCapabilities(resource));
capabilities.add(new OsgiIdentityCapability(
resource,
getSubsystemSymbolicNameHeader().getSymbolicName(),
getSubsystemVersionHeader().getVersion(),
getSubsystemTypeHeader().getType()));
capabilities.trimToSize();
return capabilities;
}
public List<Requirement> toRequirements(Resource resource) {
ArrayList<Requirement> requirements = new ArrayList<Requirement>();
for (Header<?> header : headers.values())
if (header instanceof RequirementHeader && !((header instanceof SubsystemContentHeader) || (header instanceof PreferredProviderHeader)))
requirements.addAll(((RequirementHeader<?>)header).toRequirements(resource));
requirements.trimToSize();
return requirements;
}
public void write(OutputStream out) throws IOException {
Manifest manifest = new Manifest();
Attributes attributes = manifest.getMainAttributes();
// The manifest won't write anything unless the following header is present.
attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
for (Entry<String, Header<?>> entry : headers.entrySet()) {
attributes.putValue(entry.getKey(), entry.getValue().getValue());
}
manifest.write(out);
}
}