package org.apache.aries.subsystem.scope.impl;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.aries.subsystem.scope.Scope;
import org.apache.aries.subsystem.scope.SharePolicy;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.InvalidSyntaxException;
public class Scopes {
private final BundleContext bundleContext;
private final Map<Bundle, ScopeImpl> bundleToScope = Collections.synchronizedMap(new HashMap<Bundle, ScopeImpl>());
private final IdGenerator idGenerator;
private final SortedMap<Long, ScopeImpl> idToScope = Collections.synchronizedSortedMap(new TreeMap<Long, ScopeImpl>());
public Scopes(BundleContext bundleContext) {
this.bundleContext = bundleContext;
selectAll();
for (Bundle bundle : bundleContext.getBundles()) {
if (contains(bundle)) {
continue;
}
addBundle(bundle);
}
if (idToScope.isEmpty()) {
idGenerator = new IdGenerator(0);
}
else {
idGenerator = new IdGenerator(idToScope.lastKey() + 1);
}
}
public synchronized void addBundle(Bundle bundle) {
addBundle(bundle, getRootScope());
}
public synchronized void addBundle(Bundle bundle, ScopeImpl scope) {
bundleToScope.put(bundle, scope);
scope.addBundle(bundle);
insert(scope);
}
public synchronized void addScope(ScopeImpl scope) {
idToScope.put(scope.getId(), scope);
for (Bundle bundle : scope.getBundles()) {
bundleToScope.put(bundle, scope);
}
ScopeImpl parent = (ScopeImpl)scope.getParent();
if (parent != null) {
parent.addChild(scope);
}
insert(scope);
for (Scope child : scope.getChildren()) {
addScope((ScopeImpl)child);
}
}
public synchronized void clear() {
idToScope.clear();
bundleToScope.clear();
}
public synchronized boolean contains(Bundle bundle) {
return bundleToScope.containsKey(bundle);
}
public synchronized ScopeImpl getRootScope() {
ScopeImpl scope = idToScope.get(0L);
if (scope == null) {
scope = new ScopeImpl(0, "root", null, -1, Arrays.asList(bundleContext.getBundles()), new SharePolicies(), this);
addScope(scope);
}
return scope;
}
public synchronized ScopeImpl getScope(Long id) {
return idToScope.get(id);
}
public synchronized ScopeImpl getScope(Bundle bundle) {
ScopeImpl scope = bundleToScope.get(bundle);
if (scope == null) {
addBundle(bundle);
scope = getRootScope();
}
return scope;
}
public long nextScopeId() {
return idGenerator.nextId();
}
public synchronized void removeBundle(Bundle bundle) {
ScopeImpl scope = bundleToScope.remove(bundle);
if (scope != null) {
synchronized (scope) {
scope.removeBundle(bundle);
}
insert(scope);
}
}
public synchronized void removeScope(ScopeImpl scope) {
for (Scope child : scope.getChildren()) {
removeScope((ScopeImpl)child);
}
idToScope.remove(scope.getId());
for (Bundle bundle : scope.getBundles()) {
bundleToScope.remove(bundle);
}
ScopeImpl parent = (ScopeImpl)scope.getParent();
if (parent != null) {
parent.removeChild(scope);
}
delete(scope);
}
private void delete(ScopeImpl scope) {
File file = bundleContext.getDataFile("scope" + scope.getId());
if (file == null) return;
file.delete();
}
private void insert(ScopeImpl scope) {
File file = bundleContext.getDataFile("scope" + scope.getId());
if (file == null) return;
DataOutputStream dos = null;
try {
dos = new DataOutputStream(new FileOutputStream(file));
insertScope(scope, dos);
}
catch (IOException e) {
// TODO Log this. Remove print stack trace.
e.printStackTrace();
}
finally {
if (dos != null) {
try {
dos.close();
}
catch (IOException e) {}
}
}
}
private void insertBundles(Collection<Bundle> bundles, DataOutputStream dos) throws IOException {
for (Bundle bundle : bundles) {
dos.writeLong(bundle.getBundleId());
}
dos.writeLong(-1);
}
private void insertScope(ScopeImpl scope, DataOutputStream dos) throws IOException {
dos.writeLong(scope.getId());
dos.writeUTF(scope.getName());
dos.writeUTF(scope.getLocation() == null ? "" : scope.getLocation());
dos.writeLong(scope.getParent() == null ? -1 : scope.getParent().getId());
insertBundles(scope.getBundles(), dos);
insertSharePolicies(scope.getSharePolicies(SharePolicy.TYPE_EXPORT), dos);
insertSharePolicies(scope.getSharePolicies(SharePolicy.TYPE_IMPORT), dos);
}
private void insertSharePolicies(Map<String, List<SharePolicy>> sharePolicies, DataOutputStream dos) throws IOException {
for (String namespace : sharePolicies.keySet()) {
insertSharePolicies(sharePolicies.get(namespace), dos);
}
}
private void insertSharePolicies(List<SharePolicy> sharePolicies, DataOutputStream dos) throws IOException {
for (SharePolicy sharePolicy : sharePolicies) {
dos.writeUTF(sharePolicy.getType());
dos.writeUTF(sharePolicy.getNamespace());
dos.writeUTF(sharePolicy.getFilter().toString());
}
}
private void selectAll() {
File file = bundleContext.getDataFile("");
if (file == null) {
return;
}
File[] files = file.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.startsWith("scope");
}
});
if (files == null || files.length == 0) {
return;
}
for (File f : files) {
DataInputStream dis = null;
try {
dis = new DataInputStream(new FileInputStream(f));
addScope(selectScope(dis, bundleContext));
}
catch (Exception e) {
// TODO Log this. Remove print stack trace.
e.printStackTrace();
}
finally {
if (dis != null) {
try {
dis.close();
}
catch (IOException e) {}
}
}
}
}
private Collection<Bundle> selectBundles(DataInputStream dis, BundleContext bundleContext) throws IOException {
Collection<Bundle> bundles = new ArrayList<Bundle>();
long bundleId;
while ((bundleId = dis.readLong()) != -1) {
Bundle bundle = bundleContext.getBundle(bundleId);
if (bundle != null) {
bundles.add(bundle);
}
}
return bundles;
}
private ScopeImpl selectScope(DataInputStream dis, BundleContext bundleContext) throws InvalidSyntaxException, IOException {
long id = dis.readLong();
String name = dis.readUTF();
String location = dis.readUTF();
long parentId = dis.readLong();
Collection<Bundle> bundles = selectBundles(dis, bundleContext);
SharePolicies sharePolicies = selectSharePolicies(dis);
return new ScopeImpl(id, name, location, parentId, bundles, sharePolicies, this);
}
private SharePolicies selectSharePolicies(DataInputStream dis) throws InvalidSyntaxException, IOException {
SharePolicies sharePolicies = new SharePolicies();
while (true) {
try {
String type = dis.readUTF();
String namespace = dis.readUTF();
String filter = dis.readUTF();
sharePolicies.addSharePolicy(new SharePolicy(type, namespace, FrameworkUtil.createFilter(filter)));
}
catch (EOFException e) {
break;
}
}
return sharePolicies;
}
}