blob: 0d27785b81befa18aeb44ce902f3d0bd0e5e1acc [file] [log] [blame]
/*
* 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 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.ace.deployment.provider.impl;
import java.net.URL;
import java.util.Map;
import java.util.jar.Attributes;
import org.apache.ace.deployment.provider.ArtifactData;
import org.osgi.framework.Constants;
import aQute.bnd.annotation.ConsumerType;
/**
* Implementation of <code>ArtifactData</code>. It overrides equals to make comparisons between versions easier.
*/
@ConsumerType
public class ArtifactDataImpl implements ArtifactData {
public final static String HEADER_NAME = "Name";
public static final String CUSTOMIZER = "DeploymentPackage-Customizer";
public static final String PROCESSORPID = "Resource-Processor";
/**
* Key, intended to be used for artifacts which are bundles and will publish
* a resource processor (see OSGi compendium section 114.10).
*/
public static final String DIRECTIVE_ISCUSTOMIZER = "DeploymentPackage-Customizer";
/**
* Key, intended to be used for resources which require a resource processor
* (see OSGi compendium section 114.10).
*/
public static final String DIRECTIVE_KEY_PROCESSORID = "Resource-Processor";
/**
* Key, intended to be used for artifacts which have a resourceID that's different
* from their generated name (based on URL).
*/
public static final String DIRECTIVE_KEY_RESOURCE_ID = "Resource-ID";
/**
* Key, intended to be used for matching processed (see ArtifactPreprocessor) to their
* 'original' one.
*/
public static final String DIRECTIVE_KEY_BASEURL = "Base-Url";
public static final String REPOSITORY_PATH = "ACE-RepositoryPath";
private final String m_filename;
private final String m_symbolicName;
private final String m_version;
private final Map<String, String> m_directives;
private final URL m_url;
private volatile boolean m_hasChanged;
/**
* Constructs an ArtifactDataImpl object.
* @param url The URL to the bundle. It will also be used to create the filename.
* The file-part of the url (after the last /) should It must only contain characters [A-Za-z0-9._-].
* @param directives A map of extra directives.
* @param symbolicName The symbolicname of the bundle.
* @param version The version of the bundle. If this is <code>null</code> or empty, it will be
* normalized to "0.0.0".
* @param hasChanged Indication of whether this bundle has changed relative to the previous deployment.
*/
public ArtifactDataImpl(URL url, Map<String, String> directives, String symbolicName, String version, boolean hasChanged) {
this(url, symbolicName, version, null, directives, hasChanged);
}
/**
* Constructs an ArtifactDataImpl object.
* @param url The URL to the bundle. It will also be used to create the filename.
* The file-part of the url (after the last /) should It must only contain characters [A-Za-z0-9._-].
* @param directives A map of extra directives.
* @param hasChanged Indication of whether this bundle has changed relative to the previous deployment.
*/
public ArtifactDataImpl(URL url, Map<String, String> directives, boolean hasChanged) {
this(url, null, null, null, directives, hasChanged);
}
public ArtifactDataImpl(String filename, URL url, Map<String, String> directives, boolean hasChanged) {
this(url, null, null, filename, directives, hasChanged);
}
/**
* Constructs an ArtifactDataImpl object.
* @param filename The filename of the bundle. If passed, it must only contain characters [A-Za-z0-9._-]; can be null.
* @param symbolicName The symbolicname of the bundle.
* @param version The version of the bundle. If this is <code>null</code> or empty, it will be
* normalized to "0.0.0".
* @param url The URL to the bundle. If filename is null, this will be used to create the filename; hence, the file-part of
* the url (after the last /) should adhere to the same rules as filename.
* @param hasChanged Indication of whether this bundle has changed relative to the previous deployment.
*/
public ArtifactDataImpl(String filename, String symbolicName, String version, URL url, boolean hasChanged) {
this(url, symbolicName, version, filename, null, hasChanged);
}
private ArtifactDataImpl(URL url, String symbolicName, String version, String filename, Map<String, String> directives, boolean hasChanged) {
m_url = url;
if (filename != null) {
m_filename = filename;
}
else {
String urlString = m_url.toString();
m_filename = (urlString == null) ? null : urlString.substring(urlString.lastIndexOf('/') + 1);
}
for (byte b : m_filename.getBytes()) {
if (!(((b >= 'A') && (b <= 'Z')) || ((b >= 'a') && (b <= 'z')) || ((b >= '0') && (b <= '9')) || (b == '.') || (b == '-') || (b == '_'))) {
throw new IllegalArgumentException("Filename " + m_filename + " " + (filename == null ? "constructed from the url" : "") + " contains an illegal character '" + new String(new byte[] {b}) + "'");
}
}
m_symbolicName = symbolicName;
if ((version == null) || (version.trim().length() == 0)) {
m_version = "0.0.0";
}
else {
m_version = version;
}
m_directives = directives;
m_hasChanged = hasChanged;
}
public String getFilename() {
return m_filename;
}
public String getSymbolicName() {
return m_symbolicName;
}
public String getVersion() {
return m_version;
}
public String getProcessorPid() {
if (m_directives != null) {
return m_directives.get(DIRECTIVE_KEY_PROCESSORID);
}
return null;
}
public URL getUrl() {
return m_url;
}
public boolean hasChanged() {
return m_hasChanged;
}
/**
* @param hasChanged Indicate the bundle has changed
*/
public void setChanged(boolean hasChanged) {
m_hasChanged = hasChanged;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof ArtifactDataImpl)) {
return false;
}
ArtifactDataImpl jarFile2 = (ArtifactDataImpl) other;
if (getSymbolicName() != null) {
// this is a bundle
return getSymbolicName().equals(jarFile2.getSymbolicName()) &&
getVersion().equals(jarFile2.getVersion());
}
else {
// this is another artifact.
return m_url.equals(jarFile2.getUrl());
}
}
@Override
public int hashCode() {
int result = 11;
if (getSymbolicName() != null) {
result = result ^ getSymbolicName().hashCode();
}
result = result ^ getVersion().hashCode();
result = result ^ getUrl().hashCode();
return result;
}
public Attributes getManifestAttributes(boolean fixPackage) {
Attributes a = new Attributes();
if (!isBundle()) {
// this is a regular artifact
a.putValue(PROCESSORPID, getProcessorPid());
}
else {
a.putValue(Constants.BUNDLE_SYMBOLICNAME, getSymbolicName());
a.putValue(Constants.BUNDLE_VERSION, getVersion());
// this is a bundle
if (isCustomizer()) {
a.putValue(CUSTOMIZER, "true");
}
}
if (m_directives != null) {
String path = m_directives.get(REPOSITORY_PATH);
if (path != null) {
a.putValue(REPOSITORY_PATH, path);
}
}
if (!hasChanged() && fixPackage) {
a.putValue("DeploymentPackage-Missing", "true");
}
return a;
}
public boolean isCustomizer() {
return (m_directives != null) && "true".equals(m_directives.get(DIRECTIVE_ISCUSTOMIZER));
}
public boolean isBundle() {
return getSymbolicName() != null;
}
}