/*
* 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.sling.installer.api;
import java.io.InputStream;
import java.util.Dictionary;
/**
* A piece of data that can be installed by the {@link OsgiInstaller}
* Currently the OSGi installer supports bundles and configurations,
* but it can be extended by additional task factories supporting
* other formats.
*
* The installable resource contains as much information as the client
* can provide. An input stream or dictionary is mandatory everything
* else is optional. All optional values will be tried to be evaluated
* by the OSGi installer. If such evaluation fails the resource will
* be ignore during installation.
*
* If the client provides a configuration it should use the
* resource type {@link #TYPE_PROPERTIES}. Otherwise the resource
* type {@link #TYPE_FILE} should be used. These two generic types
* are transformed by resource transformer services to the appropriate
* resource type like bundle or configuration etc. This frees the
* client from having any knowledge about the provided data.
* However, if the client has the knowledge about the data it can
* provided a specific resource type.
*
* The provider should provide a digest for files (input streams).
* The installer will calculate a digest for dictionaries, regardless
* if the provider provided a dictionary.
*/
public class InstallableResource {
/**
* The type for properties - in this case {@link #getDictionary()}
* should contain a dictionary or the {@link #getInputStream()}
* should point to a property or configuration file.
* @since 3.1 */
public static final String TYPE_PROPERTIES = "properties";
/**
* The type for all other provided data like a bundle etc.
* In this case {@link #getInputStream()} must return an input
* stream to the data. {@link #getDictionary()} might return
* additional information.
* @since 3.1 */
public static final String TYPE_FILE = "file";
/**
* The type for a bundle - in this case {@link #getInputStream} must
* return an input stream to the bundle. {@link #getDictionary()} might
* return additional information.
* This type should only be used if the client really knows that the
* provided data is a bundle.
*/
public static final String TYPE_BUNDLE = "bundle";
/**
* The type for a configuration - in this case {@link #getDictionary()}
* must return a dictionary with the configuration.
* This type should only be used if the client really knows that the
* provided data is an OSGi configuration.
*/
public static final String TYPE_CONFIG = "config";
/**
* Optional parameter in the dictionary if a bundle is installed. If this
* is set with a valid start level, the bundle is installed in that start level.
*/
public static final String BUNDLE_START_LEVEL = "bundle.startlevel";
/**
* Optional parameter in the dictionary if a resource (not a dict) is installed.
* This parameter might be used by the installation task for any purpose like
* bundle start level etc.
* @since 3.1
*/
public static final String INSTALLATION_HINT = "installation.hint";
/**
* Optional parameter in the dictionary if a resource (not a dict) is installed.
* If this parameter is specified, the installer uses the URI to get the input
* stream of the resource! Usually the installer copies the resource into the
* file system and uses this copy. To optimize this, if the URI of the resource
* is always available (like a file URI), this property can be used to avoid
* copying the resource.
* It is only evaluated if the resource type is either unknown (null) or
* {@link #TYPE_FILE} and a digest for the resource is delivered.
* The value of this property is a string.
* This property might also be set for an {@link UpdateHandler} in order
* to give a hint for the (file) name the resource or dictionary should
* have.
* @since 3.1.2
*/
public static final String RESOURCE_URI_HINT = "resource.uri.hint";
/**
* Optional parameter to be passed in the dictionary.
* If this property is set (the value is ignored), this artifact acts like a template:
* If the artifact is changed into a new artifact and later this new artifact is deleted,
* the installer will not revert to the template. Without this property, the installer
* would install the original artifact again.
* For example: if a configuration is installed and then changed through configuration
* admin, a new artifact for the new configuration is created and managed.
* If now this configuration is deleted through configuration admin and the original
* configuration is not marked as a template, the original configuration is applied:
* the delete through config admin is not a remove of the configuration but a revert
* to the initial version.
* If the initial configuration is marked as template with this property, the removal
* of the changed configuration results in a real removal.
*
* @since 3.2.0
*/
public static final String RESOURCE_IS_TEMPLATE = "org.apache.sling.installer.api.template";
/** Default resource priority */
public static final int DEFAULT_PRIORITY = 100;
private final String id;
private final String digest;
private final InputStream inputStream;
private final Dictionary<String, Object> dictionary;
private final int priority;
private final String resourceType;
/**
* Create a data object - this is a simple constructor just using the
* values as they are provided.
* @param id Unique id for the resource, For auto detection of the resource
* type, the id should contain an extension like .jar, .cfg etc.
* @param is The input stream to the data or
* @param dict A dictionary with data
* @param digest A digest of the data - providers should make sure to set
* a digest. Calculating a digest by the installer can be very
* expensive for input streams
* @param type The resource type if known, otherwise {@link #TYPE_PROPERTIES}
* or {@link #TYPE_FILE}
* @param priority Optional priority - if not specified {@link #DEFAULT_PRIORITY}
* is used
* @throws IllegalArgumentException if something is wrong
*/
public InstallableResource(final String id,
final InputStream is,
final Dictionary<String, Object> dict,
final String digest,
final String type,
final Integer priority) {
if ( id == null ) {
throw new IllegalArgumentException("id must not be null.");
}
if ( is == null ) {
// if input stream is null, config through dictionary is expected!
if ( dict == null ) {
throw new IllegalArgumentException("dictionary must not be null (or input stream must not be null).");
}
}
this.id = id;
this.inputStream = is;
this.dictionary = dict;
this.digest = digest;
this.priority = (priority != null ? priority : DEFAULT_PRIORITY);
this.resourceType = type;
}
/**
* Return this data's id. It is opaque for the {@link OsgiInstaller}
* but should uniquely identify the resource within the namespace of
* the used installation mechanism.
* @return The id.
*/
public String getId() {
return this.id;
}
/**
* Return the type of this resource.
* @return The resource type or <code>null</code> if the type is unknown for the client.
*/
public String getType() {
return this.resourceType;
}
/**
* Return an input stream with the data of this resource.
* Null if resource contains a configuration instead. Caller is responsible for
* closing the stream.
* If this resource is of type CONFIG it must not return an input stream and
* if this resource is of type BUNDLE it must return an input stream!
* @return The input stream or null.
*/
public InputStream getInputStream() {
return this.inputStream;
}
/**
* Return this resource's dictionary.
* Null if resource contains an InputStream instead. If this resource is of
* type CONFIG it must return a dictionary and if this resource is of type BUNDLE
* it might return a dictionary!
* @return The resource's dictionary or null.
*/
public Dictionary<String, Object> getDictionary() {
return this.dictionary;
}
/**
* Return this resource's digest. Not necessarily an actual md5 or other digest of the
* data, can be any string that changes if the data changes.
* @return The digest or null
*/
public String getDigest() {
return this.digest;
}
/**
* Return the priority of this resource. Priorities are used to decide which
* resource to install when several are registered for the same OSGi entity
* (bundle, config, etc.)
* @return The priority.
*/
public int getPriority() {
return this.priority;
}
@Override
public String toString() {
return getClass().getSimpleName() + ", priority=" + priority + ", id=" + id;
}
}