/*
* Copyright 2013 Christoph Läubrich
*
* 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.ops4j.pax.exam.cm;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.ops4j.pax.exam.CoreOptions;
import org.ops4j.pax.exam.TestContainerException;
import org.ops4j.pax.exam.cm.internal.ConfigurationOptionActivator;
import org.ops4j.pax.exam.cm.internal.ConfigurationOptionConfigurationListener;
import org.ops4j.pax.exam.options.ProvisionOption;
import org.ops4j.pax.tinybundles.core.TinyBundle;
import org.ops4j.pax.tinybundles.core.TinyBundles;
import org.osgi.framework.Constants;
/**
* Implementation of the {@link ConfigurationOption} interface used internally when construction
* such options
*/
public class ConfigurationProvisionOption implements org.ops4j.pax.exam.cm.ConfigurationOption {
private final String id;
private final Map<String, Object> properties;
private boolean create = true;
private boolean override;
private boolean factory;
/**
* Creates a new {@link ConfigurationOption} for the given id and the given property values
*
* @param id configuration PID
* @param properties configuration properties
*/
public ConfigurationProvisionOption(String id, Map<String, Object> properties) {
this.id = id;
this.properties = properties;
}
/**
* @return the current value of id
*/
@Override
public String getId() {
return id;
}
/**
* Add the key/value pair to the overriden options
*
* @param key property key
* @param value property value
* @return <code>this</code> for chaining
*/
@Override
public ConfigurationOption put(String key, Object value) {
properties.put(key, value);
return this;
}
@Override
public ConfigurationOption putAll(Map<String, ?> _properties) {
this.properties.putAll(_properties);
return this;
}
/**
* @return the current value of overrideValues
*/
@Override
public Map<String, ?> getProperties() {
return properties;
}
/**
* Specify if the configuration should be created if it does not yet exits
*
* @param _create should this option be created?
* @return <code>this</code> for chaining
*/
@Override
public ConfigurationOption create(boolean _create) {
this.create = _create;
return this;
}
/**
* Specify if the properties of an existing configuration should be overriden/extended by the
* ones given here, <b>this does not work with factories!</b>
*
* @param _override should existing properties be overridden
* @return <code>this</code> for chaining
*/
@Override
public ConfigurationOption override(boolean _override) {
this.override = _override;
return this;
}
/**
* Specify if the target of the properties are a factory configuration
*
* @param _factory is this a factory configuration?
* @return <code>this</code> for chaining
*/
@Override
public ConfigurationOption factory(boolean _factory) {
this.factory = _factory;
return this;
}
/**
* @return <code>true</code> if this configuration should be created if not exits,
* <code>false</code> otherwhise
*/
@Override
public boolean isCreate() {
return create;
}
/**
* @return <code>true</code> if existing configurations should be extended/ovewritten
* <code>false</code> otherwhise
*/
@Override
public boolean isOverride() {
return override;
}
/**
* @return <code>true</code> if a factory configuration should be created <code>false</code>
* otherwhise
*/
@Override
public boolean isFactory() {
return factory;
}
@Override
public ProvisionOption<?> asOption() {
return createProvisionOption(this);
}
private static ProvisionOption<?> createProvisionOption(ConfigurationOption configOption) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream os;
try {
os = new ObjectOutputStream(outputStream);
}
catch (IOException e) {
throw new TestContainerException("can't write stream headers", e);
}
String id = configOption.getId();
if (id == null) {
throw new TestContainerException("ConfigurationOption id can't be null");
}
try {
os.writeObject(id);
os.writeBoolean(configOption.isCreate());
os.writeBoolean(configOption.isOverride());
os.writeBoolean(configOption.isFactory());
Map<String, ?> properties = configOption.getProperties();
if (properties == null) {
throw new TestContainerException("ConfigurationOption properties can't be null");
}
try {
os.writeObject(new HashMap<String, Object>(properties));
}
catch (NotSerializableException e) {
throw new TestContainerException(
"One of the values of the ConfigurationOption properties are not serializable",
e);
}
os.flush();
os.close();
}
catch (IOException e) {
throw new TestContainerException("Writing object data failed", e);
}
ByteArrayInputStream stream = new ByteArrayInputStream(outputStream.toByteArray());
TinyBundle bundle = TinyBundles.bundle();
bundle.add(ConfigurationOptionConfigurationListener.class);
bundle.add(ConfigurationOptionActivator.class).add("override.obj", stream);
bundle
.set(Constants.BUNDLE_SYMBOLICNAME, "PAXExamConfigurationOption-" + UUID.randomUUID());
bundle.set(Constants.IMPORT_PACKAGE,
"org.osgi.framework,org.osgi.service.cm,org.osgi.util.tracker,org.slf4j");
bundle.set(Constants.BUNDLE_ACTIVATOR, ConfigurationOptionActivator.class.getName());
bundle.set(Constants.BUNDLE_MANIFESTVERSION, "2");
return CoreOptions.streamBundle(bundle.build()).startLevel(1).start(true).update(false);
}
}