/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 WARRANTIESOR 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.application.impl;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import org.apache.aries.application.ApplicationMetadata;
import org.apache.aries.application.Content;
import org.apache.aries.application.DeploymentContent;
import org.apache.aries.application.DeploymentMetadata;
import org.apache.aries.application.InvalidAttributeException;
import org.apache.aries.application.management.AriesApplication;
import org.apache.aries.application.management.BundleInfo;
import org.apache.aries.application.management.ResolverException;
import org.apache.aries.application.utils.AppConstants;
import org.apache.aries.application.utils.FilterUtils;
import org.apache.aries.util.VersionRange;
import org.apache.aries.util.manifest.ManifestProcessor;
import org.osgi.framework.Filter;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.Version;
public class DeploymentMetadataImpl implements DeploymentMetadata {
private ApplicationMetadata _applicationMetadata;
private List<DeploymentContent> _deploymentContent = new ArrayList<DeploymentContent>();
private List<DeploymentContent> _provisionSharedContent = new ArrayList<DeploymentContent>();
private List<DeploymentContent> _deployedUseBundleContent = new ArrayList<DeploymentContent>();
private Set<Content> _deploymentImportPackage = new HashSet<Content>();
private Map<String, String> _deploymentCustomEntries = new HashMap<String, String>();
private Map<String, String> _deploymentEntries = new HashMap<String, String>();
private Collection<Filter> _deployedImportService = new ArrayList<Filter>();
public DeploymentMetadataImpl (AriesApplication app, Set<BundleInfo> bundlesRequired) throws ResolverException
{
_applicationMetadata = app.getApplicationMetadata();
_deploymentContent = new ArrayList<DeploymentContent>();
_provisionSharedContent = new ArrayList<DeploymentContent>();
_deployedUseBundleContent = new ArrayList<DeploymentContent>();
Map<String, VersionRange> appContent = new HashMap<String, VersionRange>();
for (Content c : app.getApplicationMetadata().getApplicationContents()) {
appContent.put(c.getContentName(), c.getVersion());
}
Map<String, VersionRange> useBundles = new HashMap<String, VersionRange>();
for (Content c : app.getApplicationMetadata().getUseBundles()) {
useBundles.put(c.getContentName(), c.getVersion());
}
for (BundleInfo info : bundlesRequired) {
VersionRange appContentRange = appContent.get(info.getSymbolicName());
VersionRange useBundleRange = useBundles.get(info.getSymbolicName());
DeploymentContent dp = new DeploymentContentImpl(info.getSymbolicName(), info.getVersion());
if ((appContentRange == null) && (useBundleRange == null)){
_provisionSharedContent.add(dp);
} else if (appContentRange.matches(info.getVersion())) {
_deploymentContent.add(dp);
} else if (useBundleRange.matches(info.getVersion())) {
_deployedUseBundleContent.add(dp);
}
else {
throw new ResolverException("Bundle " + info.getSymbolicName() + " at version " + info.getVersion() + " is not in the range " + appContentRange + " or " + useBundleRange);
}
}
}
/**
* Construct a DeploymentMetadata from Manifest
* @param src
* @throws IOException
*/
public DeploymentMetadataImpl(Manifest mf) throws InvalidAttributeException{
_applicationMetadata = new ApplicationMetadataImpl (mf);
Attributes attributes = mf.getMainAttributes();
parseDeploymentContent(attributes.getValue(AppConstants.DEPLOYMENT_CONTENT), _deploymentContent);
parseDeploymentContent(attributes.getValue(AppConstants.DEPLOYMENT_PROVISION_BUNDLE), _provisionSharedContent);
parseDeploymentContent(attributes.getValue(AppConstants.DEPLOYMENT_USE_BUNDLE), _deployedUseBundleContent);
parseContent(attributes.getValue(AppConstants.DEPLOYMENT_IMPORT_PACKAGES), _deploymentImportPackage);
_deployedImportService = getFilters(attributes.getValue(AppConstants.DEPLOYMENTSERVICE_IMPORT));
_deploymentCustomEntries = getCustomEntries(attributes);
_deploymentEntries = getEntries(attributes);
}
public DeploymentMetadataImpl(Map<String, String> map) throws InvalidAttributeException{
Attributes attributes = new Attributes();
if (map != null) {
for (Map.Entry<String, String> entry : map.entrySet()) {
attributes.putValue(entry.getKey(), entry.getValue());
}
}
parseDeploymentContent(map.get(AppConstants.DEPLOYMENT_CONTENT), _deploymentContent);
parseDeploymentContent(map.get(AppConstants.DEPLOYMENT_PROVISION_BUNDLE), _provisionSharedContent);
parseDeploymentContent(map.get(AppConstants.DEPLOYMENT_USE_BUNDLE), _deployedUseBundleContent);
parseContent(attributes.getValue(AppConstants.DEPLOYMENT_IMPORT_PACKAGES), _deploymentImportPackage);
_deployedImportService = getFilters(attributes.getValue(AppConstants.DEPLOYMENTSERVICE_IMPORT));
_deploymentCustomEntries = getCustomEntries(attributes);
_deploymentEntries = getEntries(attributes);
}
private Collection<Attributes.Name> getDeploymentStandardHeaders() {
Collection<Attributes.Name> standardKeys = new HashSet<Attributes.Name> ();
standardKeys.add(new Attributes.Name(AppConstants.APPLICATION_MANIFEST_VERSION));
standardKeys.add(new Attributes.Name(AppConstants.DEPLOYMENT_CONTENT));
standardKeys.add(new Attributes.Name(AppConstants.DEPLOYMENT_PROVISION_BUNDLE));
standardKeys.add(new Attributes.Name(AppConstants.DEPLOYMENT_USE_BUNDLE));
standardKeys.add(new Attributes.Name(AppConstants.DEPLOYMENT_IMPORT_PACKAGES));
standardKeys.add(new Attributes.Name(AppConstants.DEPLOYMENTSERVICE_IMPORT));
standardKeys.add(new Attributes.Name(AppConstants.APPLICATION_SYMBOLIC_NAME));
standardKeys.add(new Attributes.Name(AppConstants.APPLICATION_VERSION));
return standardKeys;
}
private Collection<String> getCustomHeaders(Attributes attrs) {
Collection<String> customKeys = new HashSet<String>();
Collection<Attributes.Name> standardKeys = getDeploymentStandardHeaders();
if ((attrs != null) && (!!!attrs.isEmpty())) {
Set<Object> keys = attrs.keySet();
if ((keys != null) && (!!!keys.isEmpty())) {
for (Object eachKey : keys) {
String key = eachKey.toString();
customKeys.add(key);
}
customKeys.removeAll(standardKeys);
}
}
return customKeys;
}
private String getContentsAsString (Collection<Content> contents) {
StringBuilder builder = new StringBuilder();
boolean beginning = true;
for (Content c : contents) {
if (!!!beginning) {
builder.append(",");
}
builder.append(c);
beginning = false;
}
return builder.toString();
}
public List<DeploymentContent> getApplicationDeploymentContents() {
return Collections.unmodifiableList(_deploymentContent);
}
public List<DeploymentContent> getApplicationProvisionBundles() {
return Collections.unmodifiableList(_provisionSharedContent);
}
public ApplicationMetadata getApplicationMetadata() {
return _applicationMetadata;
}
public String getApplicationSymbolicName() {
return _applicationMetadata.getApplicationSymbolicName();
}
public Version getApplicationVersion() {
return _applicationMetadata.getApplicationVersion();
}
public void store(File f) throws FileNotFoundException, IOException{
FileOutputStream fos = new FileOutputStream (f);
store(fos);
fos.close();
}
public void store(OutputStream out) throws IOException {
// We weren't built from a Manifest, so construct one.
Manifest mf = new Manifest();
Attributes attributes = mf.getMainAttributes();
attributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(), AppConstants.MANIFEST_VERSION);
attributes.putValue(AppConstants.APPLICATION_VERSION, getApplicationVersion().toString());
attributes.putValue(AppConstants.APPLICATION_SYMBOLIC_NAME, getApplicationSymbolicName());
if ((_deploymentContent != null) && (!_deploymentContent.isEmpty())) {
attributes.putValue(AppConstants.DEPLOYMENT_CONTENT, getDeploymentContentsAsString(_deploymentContent));
}
if ((_provisionSharedContent != null) && (!_provisionSharedContent.isEmpty())) {
attributes.putValue(AppConstants.DEPLOYMENT_PROVISION_BUNDLE, getDeploymentContentsAsString(_provisionSharedContent));
}
if ((_deployedUseBundleContent != null) && (!_deployedUseBundleContent.isEmpty())) {
attributes.putValue(AppConstants.DEPLOYMENT_USE_BUNDLE, getDeploymentContentsAsString(_deployedUseBundleContent));
}
if ((_deploymentImportPackage != null) && (!_deploymentImportPackage.isEmpty())) {
attributes.putValue(AppConstants.DEPLOYMENT_IMPORT_PACKAGES, getContentsAsString(_deploymentImportPackage));
}
if ((_deployedImportService != null) && (!!!_deployedImportService.isEmpty())) {
attributes.putValue(AppConstants.DEPLOYMENTSERVICE_IMPORT, convertFiltersToString(_deployedImportService, ",") );
}
// let's write out the custom headers
if ((_deploymentCustomEntries != null) && (_deploymentCustomEntries.isEmpty())) {
for (Map.Entry<String, String> customEntry : _deploymentCustomEntries.entrySet()) {
attributes.putValue(customEntry.getKey(), customEntry.getValue());
}
}
mf.write(out);
}
private String getDeploymentContentsAsString (List<DeploymentContent> content) {
StringBuilder builder = new StringBuilder();
for (DeploymentContent dc : content) {
builder.append(dc.getContentName());
builder.append(';' + AppConstants.DEPLOYMENT_BUNDLE_VERSION + "=");
builder.append(dc.getExactVersion());
builder.append(",");
}
if (builder.length() > 0) {
builder.deleteCharAt(builder.length() - 1);
}
return builder.toString();
}
private void parseDeploymentContent(String content, List<DeploymentContent> contents)
{
List<String> pcList = ManifestProcessor.split(content, ",");
for (String s : pcList) {
contents.add(new DeploymentContentImpl(s));
}
}
private void parseContent(String content, Collection<Content> contents)
{
List<String> pcList = ManifestProcessor.split(content, ",");
for (String s : pcList) {
contents.add(new ContentImpl(s));
}
}
public List<DeploymentContent> getDeployedUseBundle()
{
return Collections.unmodifiableList(_deployedUseBundleContent);
}
public Set<Content> getImportPackage()
{
return Collections.unmodifiableSet(_deploymentImportPackage);
}
public Collection<Filter> getDeployedServiceImport()
{
return Collections.unmodifiableCollection(_deployedImportService);
}
public Map<String, String> getHeaders()
{
return Collections.unmodifiableMap(_deploymentEntries);
}
private Map<String, String> getEntries(Attributes attrs) {
Map<String, String> entries = new HashMap<String, String>();
if ((attrs != null) && (!attrs.isEmpty())) {
Set<Object> keys = attrs.keySet();
for (Object key : keys) {
entries.put(key.toString(), attrs.getValue((Attributes.Name)key));
}
}
return entries;
}
private Map<String, String> getCustomEntries(Attributes attrs) {
Map<String, String> customEntry = new HashMap<String, String> ();
Collection<String> customHeaders = getCustomHeaders(attrs);
if ((customHeaders != null) && (customHeaders.isEmpty())) {
for (String customHeader : customHeaders)
customEntry.put(customHeader, attrs.getValue(customHeader));
}
return customEntry;
}
private Collection<Filter> getFilters(String filterString) throws InvalidAttributeException{
Collection<Filter> filters = new ArrayList<Filter>();
List<String> fs = ManifestProcessor.split(filterString, ",");
if ((fs != null) && (!!!fs.isEmpty())) {
for (String filter : fs) {
try {
filters.add(FrameworkUtil.createFilter(FilterUtils.removeMandatoryFilterToken(filter)));
} catch (InvalidSyntaxException ise) {
InvalidAttributeException iae = new InvalidAttributeException(ise);
throw iae;
}
}
}
return filters;
}
private String convertFiltersToString(Collection<Filter> contents, String separator) {
StringBuilder newContent = new StringBuilder();
if ((contents != null) && (!!!contents.isEmpty())) {
boolean beginning = true;
for (Filter content: contents) {
if (beginning)
newContent.append(separator);
newContent.append(content.toString());
beginning = false;
}
}
return newContent.toString();
}
}