blob: aa01170f03269ceb5dc632fb648035daa9c42685 [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.karaf.region.persist.internal;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import org.apache.karaf.region.persist.RegionsPersistence;
import org.apache.karaf.region.persist.internal.model.FilterAttributeType;
import org.apache.karaf.region.persist.internal.model.FilterBundleType;
import org.apache.karaf.region.persist.internal.model.FilterNamespaceType;
import org.apache.karaf.region.persist.internal.model.FilterPackageType;
import org.apache.karaf.region.persist.internal.model.FilterType;
import org.apache.karaf.region.persist.internal.model.RegionBundleType;
import org.apache.karaf.region.persist.internal.model.RegionType;
import org.apache.karaf.region.persist.internal.model.RegionsType;
import org.apache.karaf.region.persist.internal.util.ManifestHeaderProcessor;
import org.eclipse.equinox.region.Region;
import org.eclipse.equinox.region.RegionDigraph;
import org.eclipse.equinox.region.RegionFilterBuilder;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleRevision;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RegionsPersistenceImpl implements RegionsPersistence {
private static final Logger log = LoggerFactory.getLogger(RegionsPersistenceImpl.class);
private JAXBContext jaxbContext;
private RegionDigraph regionDigraph;
private Region kernel;
private Bundle digraphBundle;
private Bundle framework;
public RegionsPersistenceImpl(RegionDigraph regionDigraph, Bundle digraphBundle, Bundle framework) throws JAXBException, BundleException, IOException, InvalidSyntaxException {
log.info("Loading region digraph persistence");
this.digraphBundle = digraphBundle;
this.framework = framework;
this.regionDigraph = regionDigraph;
kernel = regionDigraph.getRegion(0);
jaxbContext = JAXBContext.newInstance(RegionsType.class);
load();
}
@Override
public void install(Bundle b, String regionName) throws BundleException {
Region region = regionDigraph.getRegion(regionName);
if (region == null) {
region = regionDigraph.createRegion(regionName);
}
kernel.removeBundle(b);
region.addBundle(b);
}
@Override
public void save() throws BundleException, IOException {
File digraphFile = digraphBundle.getBundleContext().getDataFile("digraph");
FileOutputStream digraphStream = new FileOutputStream(digraphFile);
try {
regionDigraph.getRegionDigraphPersistence().save(
regionDigraph,
digraphStream
);
} finally {
digraphStream.close();
}
}
void save(RegionsType regionsType, Writer out) throws JAXBException {
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.marshal(regionsType, out);
}
void load() throws IOException, BundleException, JAXBException, InvalidSyntaxException {
if (this.regionDigraph.getRegions().size() <= 1) {
File etc = new File(System.getProperty("karaf.etc"));
File regionsConfig = new File(etc, "regions-config.xml");
if (regionsConfig.exists()) {
log.info("initializing region digraph from etc/regions-config.xml");
Reader in = new FileReader(regionsConfig);
try {
load(this.regionDigraph, in);
} finally {
in.close();
}
} else {
log.info("no regions config file");
}
}
}
void load(RegionDigraph regionDigraph, Reader in) throws JAXBException, BundleException, InvalidSyntaxException {
RegionsType regionsType = load(in);
load(regionsType, regionDigraph);
}
RegionsType load(Reader in) throws JAXBException {
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
return (RegionsType) unmarshaller.unmarshal(in);
}
void load(RegionsType regionsType, RegionDigraph regionDigraph) throws BundleException, InvalidSyntaxException {
BundleContext frameworkContext = framework.getBundleContext();
for (RegionType regionType: regionsType.getRegion()) {
String name = regionType.getName();
log.debug("Creating region: " + name);
Region region = regionDigraph.createRegion(name);
for (RegionBundleType bundleType: regionType.getBundle()) {
if (bundleType.getId() != null) {
region.addBundle(bundleType.getId());
} else {
Bundle b = frameworkContext.getBundle(bundleType.getLocation());
region.addBundle(b);
}
}
}
for (FilterType filterType: regionsType.getFilter()) {
Region from = regionDigraph.getRegion(filterType.getFrom());
Region to = regionDigraph.getRegion(filterType.getTo());
log.debug("Creating filter between " + from.getName() + " to " + to.getName());
RegionFilterBuilder builder = regionDigraph.createRegionFilterBuilder();
for (FilterBundleType bundleType: filterType.getBundle()) {
String symbolicName = bundleType.getSymbolicName();
String version = bundleType.getVersion();
if (bundleType.getId() != null) {
Bundle b = frameworkContext.getBundle(bundleType.getId());
symbolicName = b.getSymbolicName();
version = b.getVersion().toString();
}
String namespace = BundleRevision.BUNDLE_NAMESPACE;
List<FilterAttributeType> attributeTypes = bundleType.getAttribute();
buildFilter(symbolicName, version, namespace, attributeTypes, builder);
}
for (FilterPackageType packageType: filterType.getPackage()) {
String packageName = packageType.getName();
String version = packageType.getVersion();
String namespace = BundleRevision.PACKAGE_NAMESPACE;
List<FilterAttributeType> attributeTypes = packageType.getAttribute();
buildFilter(packageName, version, namespace, attributeTypes, builder);
}
if (to == kernel) {
//add framework exports
BundleRevision rev = framework.adapt(BundleRevision.class);
List<BundleCapability> caps = rev.getDeclaredCapabilities(BundleRevision.PACKAGE_NAMESPACE);
for (BundleCapability cap : caps) {
String filter = ManifestHeaderProcessor.generateFilter(filter(cap.getAttributes()));
builder.allow(BundleRevision.PACKAGE_NAMESPACE, filter);
}
}
//TODO explicit services?
for (FilterNamespaceType namespaceType: filterType.getNamespace()) {
String namespace = namespaceType.getName();
HashMap<String, Object> attributes = new HashMap<String, Object>();
for (FilterAttributeType attributeType: namespaceType.getAttribute()) {
attributes.put(attributeType.getName(), attributeType.getValue());
}
String filter = ManifestHeaderProcessor.generateFilter(attributes);
builder.allow(namespace, filter);
}
regionDigraph.connect(from, builder.build(), to);
}
}
private Map<String, Object> filter(Map<String, Object> attributes) {
Map<String, Object> result = new HashMap<String, Object>(attributes);
result.remove("bundle-version");
result.remove("bundle-symbolic-name");
return result;
}
private void buildFilter(String packageName, String version, String namespace, List<FilterAttributeType> attributeTypes, RegionFilterBuilder builder) throws InvalidSyntaxException {
HashMap<String, Object> attributes = new HashMap<String, Object>();
if (namespace != null) {
attributes.put(namespace, packageName);
}
if (version != null) {
attributes.put("version", version);
}
for (FilterAttributeType attributeType: attributeTypes) {
attributes.put(attributeType.getName(), attributeType.getValue());
}
String filter = ManifestHeaderProcessor.generateFilter(attributes);
builder.allow(namespace, filter);
}
}