Initial commit of Sigil contribution. (FELIX-1142)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@793581 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/sigil/org.cauldron.sigil.core/.classpath b/sigil/org.cauldron.sigil.core/.classpath
new file mode 100644
index 0000000..e26ebfb
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/.classpath
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins">
+ <accessrules>
+ <accessrule kind="accessible" pattern="org/cauldron/newton/descriptor/**"/>
+ <accessrule kind="accessible" pattern="org/eclipse/pde/internal/**"/>
+ </accessrules>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry exported="true" kind="lib" path="lib/commons-lang-2.4.jar" sourcepath="org.cauldron.sigil.coresrc.zip"/>
+ <classpathentry kind="output" path="build/classes"/>
+</classpath>
diff --git a/sigil/org.cauldron.sigil.core/.project b/sigil/org.cauldron.sigil.core/.project
new file mode 100644
index 0000000..ed75ac8
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.cauldron.sigil.core</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/sigil/org.cauldron.sigil.core/.settings/org.eclipse.jdt.core.prefs b/sigil/org.cauldron.sigil.core/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ed4b35e
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+#Tue Sep 16 15:53:19 BST 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/sigil/org.cauldron.sigil.core/META-INF/MANIFEST.MF b/sigil/org.cauldron.sigil.core/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..f9bcf63
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/META-INF/MANIFEST.MF
@@ -0,0 +1,28 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: org.cauldron.sigil.core
+Bundle-SymbolicName: org.cauldron.sigil.core;singleton:=true
+Bundle-Version: 0.8.0.qualifier
+Bundle-Activator: org.cauldron.sigil.SigilCore
+Bundle-Vendor: Paremus Ltd.
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.core.expressions,
+ org.eclipse.core.runtime,
+ org.eclipse.debug.ui,
+ org.eclipse.jdt.core,
+ org.eclipse.ui,
+ org.eclipse.ui.console;bundle-version="3.3.0",
+ org.cauldron.sigil.utils,
+ org.cauldron.bld.core
+Bundle-ActivationPolicy: lazy
+Export-Package: org.cauldron.sigil,
+ org.cauldron.sigil.install,
+ org.cauldron.sigil.job,
+ org.cauldron.sigil.model.project,
+ org.cauldron.sigil.model.repository,
+ org.cauldron.sigil.model.util,
+ org.cauldron.sigil.preferences
+Bundle-ClassPath: .,
+ lib/commons-lang-2.4.jar
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Import-Package: junit.framework;version="3.8.2";resolution:=optional
diff --git a/sigil/org.cauldron.sigil.core/build.properties b/sigil/org.cauldron.sigil.core/build.properties
new file mode 100644
index 0000000..a462907
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/build.properties
@@ -0,0 +1,10 @@
+source.. = src/
+output.. = build/classes/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ lib/commons-lang-2.4.jar,\
+ schema/
+bin.excludes = META-INF/.svn/
+src.includes = src/,\
+ META-INF/
diff --git a/sigil/org.cauldron.sigil.core/plugin.xml b/sigil/org.cauldron.sigil.core/plugin.xml
new file mode 100644
index 0000000..3128c58
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/plugin.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<?eclipse version="3.2"?>
+<plugin>
+ <extension-point id="org.cauldron.sigil.repositoryprovider" name="Bundle Repository Provider" schema="schema/org.cauldron.sigil.repositoryprovider.exsd"/>
+ <extension-point id="org.cauldron.sigil.installbuilder" name="Newton Install Builder" schema="schema/org.cauldron.sigil.runtime.installbuilder.exsd"/>
+
+ <extension
+ point="org.eclipse.core.contenttype.contentTypes">
+ <content-type
+ base-type="org.eclipse.core.runtime.text"
+ file-extensions="script,nsh"
+ id="org.cauldron.sigil.content.NewtonScriptType"
+ name="Newton Script"
+ priority="normal">
+ </content-type>
+
+ </extension>
+ <extension
+ point="org.eclipse.core.expressions.propertyTesters">
+ <propertyTester
+ class="org.cauldron.sigil.property.SigilPropertyTester"
+ id="org.cauldron.sigil.property.NewtonPropertyTester"
+ namespace="org.cauldron.sigil"
+ properties="isNewtonResource,isCompositeResource,isSystemResource,isScriptResource,isSigilProject"
+ type="org.eclipse.core.resources.IResource"/>
+ </extension>
+ <extension
+ point="org.eclipse.core.runtime.adapters">
+ <factory
+ adaptableType="org.eclipse.core.resources.IFile"
+ class="org.cauldron.sigil.internal.adapter.FileAdaptorFactory">
+ <adapter type="org.cauldron.sigil.model.eclipse.ISigilBundle"/>
+ </factory>
+ <factory
+ adaptableType="org.eclipse.core.resources.IProject"
+ class="org.cauldron.sigil.internal.adapter.ProjectAdaptorFactory">
+ <adapter type="org.cauldron.sigil.model.project.ISigilProjectModel"/>
+ </factory>
+ </extension>
+ <extension
+ id="org.cauldron.sigil.core.sigilnature"
+ name="Sigil Nature"
+ point="org.eclipse.core.resources.natures">
+ <runtime>
+ <run class="org.cauldron.sigil.nature.SigilProjectNature"/>
+ </runtime>
+ </extension>
+ <extension
+ id="sigilBuilder"
+ name="Sigil Bundle Builder"
+ point="org.eclipse.core.resources.builders">
+ <builder
+ hasNature="false"
+ isConfigurable="false">
+ <run class="org.cauldron.sigil.internal.builders.SigilIncrementalProjectBuilder"/>
+ </builder>
+ </extension>
+ <extension
+ point="org.eclipse.core.runtime.preferences">
+ <initializer
+ class="org.cauldron.sigil.preferences.SigilPreferencesInitializer">
+ </initializer>
+ </extension>
+ <extension
+ point="org.cauldron.sigil.repositoryprovider">
+ <provider
+ class="org.cauldron.sigil.internal.repository.eclipse.WorkspaceRepositoryProvider"
+ defaultLevel="-3"
+ dynamic="false"
+ id="org.cauldron.sigil.core.workspaceprovider"
+ type="Workspace Repository">
+ </provider>
+ <provider
+ class="org.cauldron.bld.core.repository.FileSystemRepositoryProvider"
+ dynamic="true"
+ id="org.cauldron.sigil.core.file"
+ type="File System Repository">
+ </provider>
+ </extension>
+ <extension
+ id="org.cauldron.sigil.unresolvedDependencyMarker"
+ name="Unresolved Dependency"
+ point="org.eclipse.core.resources.markers">
+ <persistent
+ value="true">
+ </persistent>
+ <super
+ type="org.eclipse.core.resources.problemmarker">
+ </super>
+ <attribute
+ name="element">
+ </attribute>
+ <attribute
+ name="versionRange">
+ </attribute>
+ </extension>
+ <extension
+ id="org.cauldron.sigil.unresolvedDependencyMarker.importPackage"
+ name="Unresolved Import Package"
+ point="org.eclipse.core.resources.markers">
+ <persistent
+ value="true">
+ </persistent>
+ <super
+ type="org.cauldron.sigil.unresolvedDependencyMarker">
+ </super>
+ </extension>
+ <extension
+ id="org.cauldron.sigil.unresolvedDependencyMarker.requireBundle"
+ name="Unresolve Require Bundle"
+ point="org.eclipse.core.resources.markers">
+ <persistent
+ value="true">
+ </persistent>
+ <super
+ type="org.cauldron.sigil.unresolvedDependencyMarker">
+ </super>
+ </extension>
+</plugin>
diff --git a/sigil/org.cauldron.sigil.core/schema/org.cauldron.sigil.repositoryprovider.exsd b/sigil/org.cauldron.sigil.core/schema/org.cauldron.sigil.repositoryprovider.exsd
new file mode 100644
index 0000000..051c866
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/schema/org.cauldron.sigil.repositoryprovider.exsd
@@ -0,0 +1,158 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!--
+ 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.
+-->
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.cauldron.sigil.core" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.cauldron.sigil.core" id="org.cauldron.sigil.repository" name="Sigil Bundle Repository Provider"/>
+ </appinfo>
+ <documentation>
+ [Enter description of this extension point.]
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="provider" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="provider">
+ <complexType>
+ <attribute name="id" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="type" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn=":org.cauldron.sigil.repository.IRepositoryProvider"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="icon" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="resource"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="dynamic" type="boolean" use="default" value="true">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="defaultLevel" type="string" use="default" value="500">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ [Enter the first release in which this extension point appears.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ [Enter extension point usage example here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="apiinfo"/>
+ </appinfo>
+ <documentation>
+ [Enter API information here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="implementation"/>
+ </appinfo>
+ <documentation>
+ [Enter information about supplied implementation of this extension point.]
+ </documentation>
+ </annotation>
+
+
+</schema>
diff --git a/sigil/org.cauldron.sigil.core/schema/org.cauldron.sigil.runtime.installbuilder.exsd b/sigil/org.cauldron.sigil.core/schema/org.cauldron.sigil.runtime.installbuilder.exsd
new file mode 100644
index 0000000..3522aa4
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/schema/org.cauldron.sigil.runtime.installbuilder.exsd
@@ -0,0 +1,127 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!--
+ 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.
+-->
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.cauldron.sigil.runtime" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.cauldron.sigil.runtime" id="org.cauldron.sigil.runtime.installbuilder" name="Newton Install Builder"/>
+ </appinfo>
+ <documentation>
+ [Enter description of this extension point.]
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="builder" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="builder">
+ <complexType>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn=":org.cauldron.sigil.install.INewtonInstallBuilder"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="priority" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ [Enter the first release in which this extension point appears.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ [Enter extension point usage example here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="apiinfo"/>
+ </appinfo>
+ <documentation>
+ [Enter API information here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="implementation"/>
+ </appinfo>
+ <documentation>
+ [Enter information about supplied implementation of this extension point.]
+ </documentation>
+ </annotation>
+
+
+</schema>
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/SigilCore.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/SigilCore.java
new file mode 100644
index 0000000..b0e123e
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/SigilCore.java
@@ -0,0 +1,570 @@
+/*
+ * 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.cauldron.sigil;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.cauldron.bld.config.IBldProject;
+import org.cauldron.bld.core.BldCore;
+import org.cauldron.sigil.install.IOSGiInstallManager;
+import org.cauldron.sigil.internal.install.OSGiInstallManager;
+import org.cauldron.sigil.internal.model.project.SigilModelRoot;
+import org.cauldron.sigil.internal.model.project.SigilProject;
+import org.cauldron.sigil.internal.model.repository.RepositoryConfiguration;
+import org.cauldron.sigil.internal.repository.eclipse.GlobalRepositoryManager;
+import org.cauldron.sigil.internal.repository.eclipse.SigilRepositoryManager;
+import org.cauldron.sigil.model.ModelElementFactory;
+import org.cauldron.sigil.model.eclipse.ISigilBundle;
+import org.cauldron.sigil.model.project.ISigilModelRoot;
+import org.cauldron.sigil.model.project.ISigilProjectModel;
+import org.cauldron.sigil.model.repository.IRepositoryConfiguration;
+import org.cauldron.sigil.model.util.JavaHelper;
+import org.cauldron.sigil.repository.IBundleRepository;
+import org.cauldron.sigil.repository.IRepositoryManager;
+import org.cauldron.sigil.repository.IRepositoryVisitor;
+import org.cauldron.sigil.repository.ResolutionConfig;
+import org.eclipse.core.resources.ICommand;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceChangeEvent;
+import org.eclipse.core.resources.IResourceChangeListener;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class SigilCore extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.cauldron.sigil.core";
+ public static final String NATURE_ID = PLUGIN_ID + ".sigilnature";
+ public static final String PREFERENCES_ID = "org.cauldron.sigil.ui.preferences.SigilPreferencePage";
+ public static final String OSGI_INSTALLS_PREFERENCES_ID = "org.cauldron.sigil.ui.preferences.osgiInstalls";
+ public static final String EXCLUDED_RESOURCES_PREFERENCES_ID = "org.cauldron.sigil.ui.preferences.excludedResources";
+ public static final String REPOSITORIES_PREFERENCES_ID = "org.cauldron.sigil.ui.preferences.repositoriesPreferencePage";
+ public static final String OSGI_SCRIPT_TYPE = "org.cauldron.sigil.content.OSGiScriptType";
+ public static final String SIGIL_PROJECT_FILE = IBldProject.PROJECT_FILE;
+ public static final String BUILDER_ID = PLUGIN_ID + ".sigilBuilder";
+ public static final String CLASSPATH_CONTAINER_PATH = PLUGIN_ID + ".classpathContainer";
+
+ public static final String OSGI_INSTALLS = "org.cauldron.osgi.installs";
+ public static final String OSGI_DEFAULT_INSTALL_ID = "org.cauldron.osgi.default.install.id";
+ public static final String OSGI_INSTALL_PREFIX = "org.cauldron.osgi.install.";
+ public static final String OSGI_SOURCE_LOCATION = "org.cauldron.osgi.source.location";
+ public static final String OSGI_INSTALL_CHECK_PREFERENCE = "org.cauldron.osgi.install.check";
+ public static final String LIBRARY_KEYS_PREF = "org.cauldron.osgi.library.keys";
+ public static final String PREFERENCES_REBUILD_PROJECTS = "org.cauldron.sigil.rebuild.projects";
+ public static final String QUALIFY_VERSIONS = "org.cauldron.sigil.qualify.versions";
+
+ public static final String DEFAULT_VERSION_LOWER_BOUND = "org.cauldron.sigil.versionLowerBound";
+ public static final String DEFAULT_VERSION_UPPER_BOUND = "org.cauldron.sigil.versionUpperBound";
+
+ public static final String DEFAULT_EXCLUDED_RESOURCES = "org.cauldron.sigil.excludedResources";
+ public static final String PREFERENCES_NOASK_OSGI_INSTALL = "org.cauldron.sigil.noAskOSGIHome";
+ public static final String PREFERENCES_ADD_IMPORT_FOR_EXPORT = "org.cauldron.sigil.addImportForExport";
+ public static final String INCLUDE_OPTIONAL_DEPENDENCIES = "org.cauldron.sigil.includeOptionalDependencies";
+
+ public static final String INSTALL_BUILDER_EXTENSION_POINT_ID = "org.cauldron.sigil.installbuilder";
+ public static final String REPOSITORY_PROVIDER_EXTENSION_POINT_ID = "org.cauldron.sigil.repositoryprovider";
+
+ public static final String MARKER_UNRESOLVED_DEPENDENCY = "org.cauldron.sigil.unresolvedDependencyMarker";
+ public static final String MARKER_UNRESOLVED_IMPORT_PACKAGE = "org.cauldron.sigil.unresolvedDependencyMarker.importPackage";
+ public static final String MARKER_UNRESOLVED_REQUIRE_BUNDLE = "org.cauldron.sigil.unresolvedDependencyMarker.requireBundle";
+ public static final String REPOSITORY_SET = PLUGIN_ID + ".repository.set";
+ public static final String PREFERENCES_INCLUDE_OPTIONAL = PLUGIN_ID + ".include.optional";
+
+ private static final Object NULL = new Object();
+
+ // The shared instance
+ private static SigilCore plugin;
+
+ private ServiceTracker descriptorTracker;
+ private ServiceTracker registryTracker;
+ private ServiceTracker serializerTracker;
+
+ private static IRepositoryConfiguration repositoryConfig;
+ private static OSGiInstallManager installs;
+ private static ISigilModelRoot modelRoot;
+ private static HashMap<Object, SigilRepositoryManager> repositoryManagers = new HashMap<Object, SigilRepositoryManager>();
+ private static GlobalRepositoryManager globalRepositoryManager;
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static SigilCore getDefault() {
+ return plugin;
+ }
+
+ public static CoreException newCoreException(String msg, Throwable t) {
+ return new CoreException(makeStatus(msg, t, IStatus.ERROR));
+ }
+
+ public static void log(String msg) {
+ DebugPlugin.log(makeStatus(msg, null, IStatus.INFO));
+ }
+
+ public static void error(String msg) {
+ DebugPlugin.log(makeStatus(msg, null, IStatus.ERROR));
+ }
+
+ public static void error(String msg, Throwable t) {
+ DebugPlugin.log(makeStatus(msg, t, IStatus.ERROR));
+ }
+
+ public static void warn(String msg) {
+ DebugPlugin.log(makeStatus(msg, null, IStatus.WARNING));
+ }
+
+ public static void warn(String msg, Throwable t) {
+ DebugPlugin.log(makeStatus(msg, t, IStatus.WARNING));
+ }
+
+ private static IStatus makeStatus(String msg, Throwable t, int status) {
+ if (t instanceof CoreException) {
+ CoreException c = (CoreException) t;
+ return c.getStatus();
+ } else {
+ return new Status(status, SigilCore.PLUGIN_ID, status, msg, t);
+ }
+ }
+
+ public static boolean isSigilProject(IProject resource) {
+ if ( resource == null ) return false;
+
+ if ( resource.isAccessible() && resource instanceof IProject ) {
+ IProject project = (IProject) resource;
+ try {
+ return project.hasNature(NATURE_ID);
+ } catch (CoreException e) {
+ error( e.getMessage(), e );
+ return false;
+ }
+ }
+ else {
+ return false;
+ }
+ }
+
+ public static boolean hasProjectNature(IProject project)
+ throws CoreException {
+ return project.getNature(NATURE_ID) != null;
+ }
+
+ public static ResourceBundle getResourceBundle() {
+ return ResourceBundle.getBundle("resources."
+ + SigilCore.class.getName(), Locale.getDefault(),
+ SigilCore.class.getClassLoader());
+ }
+
+ public static ISigilProjectModel create(IProject project)
+ throws CoreException {
+ if (project.hasNature(NATURE_ID)) {
+ return new SigilProject(project);
+ } else {
+ throw newCoreException("Project " + project.getName()
+ + " is not a sigil project", null);
+ }
+ }
+
+ /**
+ * The constructor
+ */
+ public SigilCore() {
+ plugin = this;
+ }
+
+ public void earlyStartup() {
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext
+ * )
+ */
+ public void start(final BundleContext context) throws Exception {
+ super.start(context);
+
+ modelRoot = new SigilModelRoot();
+
+ repositoryConfig = new RepositoryConfiguration();
+
+ installs = new OSGiInstallManager();
+
+ globalRepositoryManager = new GlobalRepositoryManager();
+
+ registerModelElements(context);
+ registerResourceListeners();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext
+ * )
+ */
+ public void stop(BundleContext context) throws Exception {
+ if (descriptorTracker != null) {
+ descriptorTracker.close();
+ descriptorTracker = null;
+ }
+
+ if (registryTracker != null) {
+ registryTracker.close();
+ registryTracker = null;
+ }
+
+ if (serializerTracker != null) {
+ serializerTracker.close();
+ serializerTracker = null;
+ }
+
+ for ( SigilRepositoryManager m : repositoryManagers.values() ) {
+ m.destroy();
+ }
+
+ repositoryManagers.clear();
+
+ globalRepositoryManager.destroy();
+ globalRepositoryManager = null;
+
+ plugin = null;
+
+ super.stop(context);
+ }
+
+
+ public static boolean isBundledPath(String bp) throws CoreException {
+ boolean bundle = JavaHelper.isCachedBundle(bp);
+
+ if (!bundle) {
+ bundle = isProjectPath(bp);
+
+ if (!bundle) {
+ for (IBundleRepository r : getGlobalRepositoryManager().getRepositories()) {
+ bundle = isBundlePath(bp, r);
+ if (bundle)
+ break;
+ }
+ }
+ }
+
+ return bundle;
+ }
+
+ private static boolean isBundlePath(final String bp, IBundleRepository r) {
+ final AtomicBoolean flag = new AtomicBoolean();
+
+ IRepositoryVisitor visitor = new IRepositoryVisitor() {
+ public boolean visit(ISigilBundle b) {
+ IPath path = b.getLocation();
+ if (path != null && path.toOSString().equals(bp)) {
+ flag.set(true);
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ };
+
+ r.accept(visitor, ResolutionConfig.INDEXED_ONLY
+ | ResolutionConfig.LOCAL_ONLY);
+
+ return flag.get();
+ }
+
+ private static boolean isProjectPath(String bp) throws CoreException {
+ for (ISigilProjectModel p : SigilCore.getRoot().getProjects()) {
+ IPath path = p.findOutputLocation();
+
+ if (path.toOSString().equals(bp)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private void registerResourceListeners() {
+ final IResourceChangeListener listener = new IResourceChangeListener() {
+ public void resourceChanged(IResourceChangeEvent event) {
+ IResourceDelta delta = event.getDelta();
+ if ( delta != null ) {
+ try {
+ delta.accept(new IResourceDeltaVisitor() {
+ public boolean visit(IResourceDelta delta) throws CoreException {
+ IResource resource = delta.getResource();
+ if(resource instanceof IProject) {
+ IProject project = (IProject) resource;
+ if ( SigilCore.isSigilProject(project) ) {
+ switch (delta.getKind()) {
+ case IResourceDelta.REMOVED:
+ case IResourceDelta.ADDED:
+ rebuildAllBundleDependencies(Job.getJobManager().createProgressGroup());
+ break;
+ }
+ }
+ // Recurse no more
+ return false;
+ }
+ return true;
+ }
+ });
+ } catch (CoreException e) {
+ error("Failed to update after change", e);
+ }
+ }
+ }
+ };
+
+ Job job = new Job("Initialising sigil resource listeners") {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ ResourcesPlugin.getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.POST_CHANGE);
+ return Status.OK_STATUS;
+ }
+ };
+ job.setSystem(true);
+ job.schedule();
+ }
+
+ private void registerModelElements(BundleContext context) {
+ // trick to get eclipse to lazy load BldCore for model elements
+ BldCore.getLicenseManager();
+ String uri = "http://sigil.codecauldron.org/xml/sigil-namespace";
+ ModelElementFactory.getInstance().register(ISigilProjectModel.class,
+ SigilProject.class, "project", "sigil", uri);
+ }
+
+ public static IOSGiInstallManager getInstallManager() {
+ return installs;
+ }
+
+ public static ISigilModelRoot getRoot() {
+ return modelRoot;
+ }
+
+ public static IRepositoryManager getGlobalRepositoryManager() {
+ return globalRepositoryManager;
+ }
+
+ public static IRepositoryManager getRepositoryManager(String set) {
+ SigilRepositoryManager manager = null;
+
+ if ( set == null ) {
+ manager = repositoryManagers.get( NULL );
+ if ( manager == null ) {
+ manager = new SigilRepositoryManager(null);
+ manager.initialise();
+ repositoryManagers.put( NULL, manager );
+ }
+ }
+ else {
+ manager = repositoryManagers.get(set);
+
+ if ( manager == null ) {
+ manager = new SigilRepositoryManager(set);
+ manager.initialise();
+ repositoryManagers.put( set, manager );
+ }
+ }
+
+ return manager;
+ }
+ public static IRepositoryManager getRepositoryManager(ISigilProjectModel model) {
+ return getRepositoryManager(loadProjectRepositorySet(model));
+ }
+
+ private static String loadProjectRepositorySet(ISigilProjectModel model) {
+ if ( model == null ) {
+ return null;
+ }
+
+ return model.getPreferences().get(REPOSITORY_SET, null );
+ }
+
+
+ public static IRepositoryConfiguration getRepositoryConfiguration() {
+ return repositoryConfig;
+ }
+
+ public static void rebuildAllBundleDependencies(IProgressMonitor monitor) {
+ Collection<ISigilProjectModel> projects = getRoot().getProjects();
+ if ( !projects.isEmpty() ) {
+ SubMonitor progress = SubMonitor.convert(monitor, projects.size()*20);
+ for ( ISigilProjectModel p : projects ) {
+ rebuild(p, progress);
+ }
+ }
+
+ monitor.done();
+ }
+
+ public static void rebuildBundleDependencies(ISigilProjectModel project, IProgressMonitor monitor) {
+ HashSet<ISigilProjectModel> affected = new HashSet<ISigilProjectModel>(project.findDependentProjects(monitor));
+ affected.add(project);
+
+ SubMonitor progress = SubMonitor.convert(monitor, affected.size()*20);
+ for (ISigilProjectModel dependent : affected) {
+ rebuild(dependent, progress);
+ }
+ }
+
+
+ private static void rebuild(ISigilProjectModel dependent, SubMonitor progress) {
+ try {
+ dependent.resetClasspath(progress.newChild(10));
+ dependent.getProject().build(IncrementalProjectBuilder.FULL_BUILD, progress.newChild(10));
+ } catch (CoreException e) {
+ SigilCore.error("Failed to rebuild " + dependent, e);
+ }
+ }
+
+ public IPath findDefaultBundleLocation(ISigilProjectModel m)
+ throws CoreException {
+ IPath loc = m.getProject().getLocation();
+ loc = loc.append(m.getJavaModel().getOutputLocation().removeFirstSegments(1));
+ loc = loc.removeLastSegments(1).append( "lib" );
+ return loc.append(m.getSymbolicName() + ".jar");
+ }
+
+ public static void makeSigilProject(IProject project,
+ IProgressMonitor monitor) throws CoreException {
+ IProjectDescription description = project.getDescription();
+
+ String[] natures = description.getNatureIds();
+ String[] newNatures = new String[natures.length + 1];
+ System.arraycopy(natures, 0, newNatures, 0, natures.length);
+ newNatures[natures.length] = SigilCore.NATURE_ID;
+ description.setNatureIds(newNatures);
+
+ ICommand sigilBuild = description.newCommand();
+ sigilBuild.setBuilderName(SigilCore.BUILDER_ID);
+
+ ICommand javaBuild = description.newCommand();
+ javaBuild.setBuilderName(JavaCore.BUILDER_ID);
+
+ description.setBuildSpec(new ICommand[] { javaBuild, sigilBuild });
+
+ project.setDescription(description, new SubProgressMonitor(monitor, 2));
+
+ IJavaProject java = JavaCore.create(project);
+ if (java.exists()) {
+ IClasspathEntry[] cp = java.getRawClasspath();
+ // XXX fix for http://jira.codecauldron.org/browse/SIGIL-304
+ if ( !isSigilOnClasspath(cp) ) {
+ ArrayList<IClasspathEntry> entries = new ArrayList<IClasspathEntry>(
+ Arrays.asList(cp));
+ entries.add(JavaCore.newContainerEntry(new Path(
+ SigilCore.CLASSPATH_CONTAINER_PATH)));
+ java.setRawClasspath(entries.toArray(new IClasspathEntry[entries
+ .size()]), monitor);
+ }
+ }
+ }
+
+ /**
+ * @param cp
+ * @return
+ */
+ private static boolean isSigilOnClasspath(IClasspathEntry[] cp) {
+ for ( IClasspathEntry e : cp ) {
+ if ( e.getEntryKind() == IClasspathEntry.CPE_CONTAINER && e.getPath().segment(0).equals(SigilCore.CLASSPATH_CONTAINER_PATH) ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static Image loadImage(URL url) throws IOException {
+ ImageRegistry registry = getDefault().getImageRegistry();
+
+ String key = url.toExternalForm();
+ Image img = registry.get( key );
+
+ if ( img == null ) {
+ img = openImage(url);
+ registry.put( key, img );
+ }
+
+ return img;
+ }
+
+ private static Image openImage(URL url) throws IOException {
+ Display display = Display.getCurrent();
+ if ( display == null ) {
+ display = Display.getDefault();
+ }
+
+ InputStream in = null;
+ try {
+ in = url.openStream();
+ return new Image(display, in);
+ }
+ finally {
+ if ( in != null ) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ error( "Failed to close stream", e );
+ }
+ }
+ }
+ }
+
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/install/IOSGiInstall.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/install/IOSGiInstall.java
new file mode 100644
index 0000000..3e91ca1
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/install/IOSGiInstall.java
@@ -0,0 +1,65 @@
+/*
+ * 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.cauldron.sigil.install;
+
+import java.util.Map;
+
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Encapsulates all information about a particular OSGi install.
+ *
+ * @author dave
+ *
+ */
+public interface IOSGiInstall {
+
+ /**
+ * A unique id which can be used to refer to this install within the eclipse runtime.
+ * @return
+ */
+ String getId();
+
+ /**
+ * Where this install is located
+ * @return
+ */
+ IPath getInstallLocation();
+
+ /**
+ * @return
+ */
+ Map<String, String> getProperties();
+
+ /**
+ * @return
+ */
+ String[] getLaunchArguments();
+
+ /**
+ * @return
+ */
+ IPath getVarDirectory();
+
+ /**
+ * @return
+ */
+ IOSGiInstallType getType();
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/install/IOSGiInstallBuilder.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/install/IOSGiInstallBuilder.java
new file mode 100644
index 0000000..ce066ea
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/install/IOSGiInstallBuilder.java
@@ -0,0 +1,27 @@
+/*
+ * 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.cauldron.sigil.install;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+
+public interface IOSGiInstallBuilder {
+ IOSGiInstall build(String id, IPath path) throws CoreException;
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/install/IOSGiInstallManager.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/install/IOSGiInstallManager.java
new file mode 100644
index 0000000..c33f746
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/install/IOSGiInstallManager.java
@@ -0,0 +1,28 @@
+/*
+ * 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.cauldron.sigil.install;
+
+public interface IOSGiInstallManager {
+ IOSGiInstall findInstall(String id);
+ String[] getInstallIDs();
+ IOSGiInstall[] getInstalls();
+ IOSGiInstall getDefaultInstall();
+ IOSGiInstallType findInstallType(String location);
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/install/IOSGiInstallType.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/install/IOSGiInstallType.java
new file mode 100644
index 0000000..f975151
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/install/IOSGiInstallType.java
@@ -0,0 +1,68 @@
+/*
+ * 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.cauldron.sigil.install;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.swt.graphics.Image;
+
+//import org.eclipse.swt.graphics.Image;
+
+public interface IOSGiInstallType {
+ /**
+ * @return
+ */
+ String getName();
+
+ /**
+ *
+ * @return
+ */
+ String getVersion();
+
+ /**
+ * @return
+ */
+ String getMainClass();
+
+ /**
+ * @return
+ */
+ String[] getClassPath();
+
+ /**
+ * @return
+ */
+ IPath getSourceLocation();
+
+ /**
+ * @return
+ */
+ IPath getJavaDocLocation();
+
+ /**
+ * Return the paths of any bundles that are started by default in this OSGi instance.
+ * @return
+ */
+ IPath[] getDefaultBundleLocations();
+
+ String getId();
+
+ Image getIcon();
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/install/OSGiInstall.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/install/OSGiInstall.java
new file mode 100644
index 0000000..633f1f3
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/install/OSGiInstall.java
@@ -0,0 +1,93 @@
+/*
+ * 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.cauldron.sigil.install;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IPath;
+
+public class OSGiInstall implements IOSGiInstall {
+
+ private String id;
+ private IPath installLocation;
+ private String[] launchArgs;
+ private Map<String, String> properties;
+ private IPath varDirectory;
+ private IOSGiInstallType type;
+
+ public IPath getVarDirectory() {
+ return varDirectory;
+ }
+
+ public void setVarDirectory(IPath varDirectory) {
+ this.varDirectory = varDirectory;
+ }
+
+ public OSGiInstall(String id) {
+ this.id = id;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public IPath getInstallLocation() {
+ return installLocation;
+ }
+
+ public void setInstallLocation(IPath installLocation) {
+ this.installLocation = installLocation;
+ }
+
+ public String[] getLaunchArguments() {
+ return launchArgs;
+ }
+
+ public void setLaunchArguments(String[] launchArgs) {
+ this.launchArgs = launchArgs;
+ }
+
+ public Map<String, String> getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Map<String,String> properties) {
+ this.properties = properties;
+ }
+
+ public String toString() {
+ return "OSGiInstall[\n" +
+ "id=" + id + "\n" +
+ "type=" + type + "\n" +
+ "installLocation=" + installLocation + "\n" +
+ "launchArgs=" + Arrays.asList(launchArgs) + "\n" +
+ "properties=" + properties + "\n" +
+ "]";
+ }
+
+ public IOSGiInstallType getType() {
+ return type;
+ }
+
+ public void setType(IOSGiInstallType type) {
+ this.type = type;
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/install/OSGiInstallType.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/install/OSGiInstallType.java
new file mode 100644
index 0000000..e584f1c
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/install/OSGiInstallType.java
@@ -0,0 +1,122 @@
+/*
+ * 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.cauldron.sigil.install;
+
+import java.util.Arrays;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.swt.graphics.Image;
+
+public class OSGiInstallType implements IOSGiInstallType {
+
+ private String id;
+ private String name;
+ private String version;
+ private String mainClass;
+ private String[] classPath;
+ private IPath javaDocLocation;
+ private IPath sourceLocation;
+ private IPath[] defaultBundleLocations;
+ private Image icon;
+
+ public Image getIcon() {
+ return icon;
+ }
+
+ public void setIcon(Image icon) {
+ this.icon = icon;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String[] getClassPath() {
+ return classPath;
+ }
+
+ public IPath[] getDefaultBundleLocations() {
+ return defaultBundleLocations;
+ }
+
+ public IPath getJavaDocLocation() {
+ return javaDocLocation;
+ }
+
+ public String getMainClass() {
+ return mainClass;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public IPath getSourceLocation() {
+ return sourceLocation;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public void setMainClass(String mainClass) {
+ this.mainClass = mainClass;
+ }
+
+ public void setClassPath(String[] classPath) {
+ this.classPath = classPath;
+ }
+
+ public void setJavaDocLocation(IPath javaDocLocation) {
+ this.javaDocLocation = javaDocLocation;
+ }
+
+ public void setSourceLocation(IPath sourceLocation) {
+ this.sourceLocation = sourceLocation;
+ }
+
+ public void setDefaultBundleLocations(IPath[] defaultBundleLocations) {
+ this.defaultBundleLocations = defaultBundleLocations;
+ }
+
+ public String toString() {
+ return "OSGiInstallType[\n" +
+ "name=" + name + "\n" +
+ "version=" + version + "\n" +
+ "mainClass=" + mainClass + "\n" +
+ "classPath=" + Arrays.asList(classPath) + "\n" +
+ "javaDocLocation=" + javaDocLocation + "\n" +
+ "sourceLocation=" + sourceLocation + "\n" +
+ "defaultBundleLocations=" + Arrays.asList(defaultBundleLocations) + "\n" +
+ "]";
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/adapter/FileAdaptorFactory.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/adapter/FileAdaptorFactory.java
new file mode 100644
index 0000000..4b63ad3
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/adapter/FileAdaptorFactory.java
@@ -0,0 +1,86 @@
+/*
+ * 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.cauldron.sigil.internal.adapter;
+
+import org.cauldron.sigil.SigilCore;
+import org.cauldron.sigil.model.ModelElementFactory;
+import org.cauldron.sigil.model.ModelElementFactoryException;
+import org.cauldron.sigil.model.eclipse.ISigilBundle;
+import org.cauldron.sigil.model.project.ISigilProjectModel;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdapterFactory;
+
+/**
+ * @author savage
+ *
+ */
+public class FileAdaptorFactory implements IAdapterFactory {
+
+ public FileAdaptorFactory() {
+
+ }
+ private Class<?>[] types = new Class<?>[] { ISigilBundle.class };
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IAdapterFactory#getAdapter(java.lang.Object, java.lang.Class)
+ */
+ @SuppressWarnings("unchecked")
+ public Object getAdapter( Object adaptableObject, Class adapterType ) {
+ Object adapted = null;
+
+ IFile file = (IFile) adaptableObject;
+
+ if ( ISigilBundle.class.equals( adapterType ) ) {
+ adapted = adaptBundle(file);
+ }
+
+ return adapted;
+ }
+
+ private Object adaptBundle(IFile file) {
+ Object adapted = null;
+ IProject project = file.getProject();
+ try {
+ if ( SigilCore.hasProjectNature( project ) ) {
+ ISigilProjectModel sigil = SigilCore.create( project );
+ ISigilBundle bundle = ModelElementFactory.getInstance().newModelElement( ISigilBundle.class );
+ bundle.setParent( sigil );
+ adapted = bundle;
+ }
+ }
+ catch ( CoreException e ) {
+ SigilCore.error( "Failed to construct bundle", e );
+ } catch (ModelElementFactoryException e) {
+ SigilCore.error( "Failed to construct bundle", e );
+ }
+
+ return adapted;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IAdapterFactory#getAdapterList()
+ */
+ @SuppressWarnings("unchecked")
+ public Class[] getAdapterList() {
+ return types;
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/adapter/ProjectAdaptorFactory.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/adapter/ProjectAdaptorFactory.java
new file mode 100644
index 0000000..4811476
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/adapter/ProjectAdaptorFactory.java
@@ -0,0 +1,71 @@
+/*
+ * 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.cauldron.sigil.internal.adapter;
+
+import org.cauldron.sigil.SigilCore;
+import org.cauldron.sigil.model.project.ISigilProjectModel;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdapterFactory;
+
+/**
+ * @author savage
+ *
+ */
+public class ProjectAdaptorFactory implements IAdapterFactory {
+
+ private Class<?>[] types = new Class<?>[] { ISigilProjectModel.class };
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IAdapterFactory#getAdapter(java.lang.Object, java.lang.Class)
+ */
+ @SuppressWarnings("unchecked")
+ public Object getAdapter( Object adaptableObject, Class adapterType ) {
+ Object adapted = null;
+
+ IProject project = (IProject) adaptableObject;
+
+ if ( ISigilProjectModel.class.equals( adapterType ) ) {
+ adapted = adaptProject(project);
+ }
+
+ return adapted;
+ }
+
+ private Object adaptProject(IProject project) {
+ try {
+ if ( SigilCore.isSigilProject(project) ) {
+ return SigilCore.create(project);
+ }
+ } catch (CoreException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IAdapterFactory#getAdapterList()
+ */
+ @SuppressWarnings("unchecked")
+ public Class[] getAdapterList() {
+ return types;
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/builders/BuildConsole.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/builders/BuildConsole.java
new file mode 100644
index 0000000..5ac8117
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/builders/BuildConsole.java
@@ -0,0 +1,42 @@
+/*
+ * 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.cauldron.sigil.internal.builders;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.console.MessageConsole;
+import org.eclipse.ui.console.MessageConsoleStream;
+
+public class BuildConsole extends MessageConsole {
+
+ private static final ImageDescriptor imageDescriptor = null;
+ private MessageConsoleStream stream;
+
+ public BuildConsole() {
+ super("Sigil Build", imageDescriptor, true);
+ }
+
+ public synchronized MessageConsoleStream getMessageStream() {
+ if ( stream == null ) {
+ stream = newMessageStream();
+ }
+ return stream;
+ }
+
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/builders/SigilIncrementalProjectBuilder.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/builders/SigilIncrementalProjectBuilder.java
new file mode 100644
index 0000000..acea59a
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/builders/SigilIncrementalProjectBuilder.java
@@ -0,0 +1,312 @@
+/*
+ * 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.cauldron.sigil.internal.builders;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.cauldron.bld.bnd.BundleBuilder;
+import org.cauldron.bld.config.IBldProject;
+import org.cauldron.sigil.SigilCore;
+import org.cauldron.sigil.model.project.ISigilProjectModel;
+import org.cauldron.sigil.model.util.JavaHelper;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaModelMarker;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.ui.console.ConsolePlugin;
+import org.eclipse.ui.console.IConsole;
+import org.eclipse.ui.console.IConsoleManager;
+import org.eclipse.ui.console.MessageConsoleStream;
+
+public class SigilIncrementalProjectBuilder extends IncrementalProjectBuilder {
+
+ @Override
+ protected IProject[] build(int kind, @SuppressWarnings("unchecked")Map args, IProgressMonitor monitor)
+ throws CoreException {
+ IProject project = getProject();
+
+ if ( checkOk( project ) ) {
+ switch ( kind ) {
+ case CLEAN_BUILD:
+ case FULL_BUILD:
+ fullBuild( project, monitor );
+ break;
+ case AUTO_BUILD:
+ case INCREMENTAL_BUILD:
+ autoBuild( project, monitor );
+ break;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @param install
+ * @param project
+ * @param monitor
+ * @throws CoreException
+ */
+ private void autoBuild(IProject project,
+ IProgressMonitor monitor) throws CoreException {
+ IResourceDelta delta = getDelta(project);
+ final boolean[] changed = new boolean[1];
+ ISigilProjectModel sigil = SigilCore.create(project);
+ final IPath bldRoot = sigil.findBundleLocation().removeLastSegments(1);
+
+ delta.accept(new IResourceDeltaVisitor() {
+ public boolean visit(IResourceDelta delta) throws CoreException {
+ if ( !changed[0] ) {
+ IResource res = delta.getResource();
+ if ( res.getType() == IResource.FILE ) {
+ changed[0] = !bldRoot.isPrefixOf(res.getLocation());
+ }
+ }
+ return !changed[0];
+ }
+ });
+
+ if ( changed[0] ) {
+ doBuild(project, monitor);
+ }
+ }
+
+ /**
+ * @param install
+ * @param project
+ * @param monitor
+ * @throws CoreException
+ */
+ private void fullBuild(IProject project,
+ IProgressMonitor monitor) throws CoreException {
+ doBuild(project, monitor);
+ }
+
+ private boolean checkOk(IProject project) throws CoreException {
+ IMarker[] markers = project.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE);
+
+ for ( IMarker m : markers ) {
+ Integer s = (Integer) m.getAttribute(IMarker.SEVERITY);
+ if ( s != null && s.equals( IMarker.SEVERITY_ERROR ) ) {
+ SigilCore.log( "Skipping " + project.getName() + " build due to unresolved errors" );
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private void doBuild(IProject project, IProgressMonitor monitor ) throws CoreException {
+ ISigilProjectModel sigil = SigilCore.create(project);
+ IBldProject bld = sigil.getBldProject();
+
+ File[] classpath = buildClasspath(sigil, monitor);
+
+ String destPattern = buildDestPattern(sigil);
+
+ Properties env = new Properties();
+
+ BundleBuilder bb = new BundleBuilder(bld, classpath, destPattern, env);
+
+ for (IBldProject.IBldBundle bundle : bld.getBundles()) {
+ String id = bundle.getId();
+ loginfo("creating bundle: " + id);
+ int nWarn = 0;
+ int nErr = 0;
+ String msg = "";
+
+ try {
+ boolean modified = bb.createBundle(bundle, false, new BundleBuilder.Log() {
+ public void warn(String msg) {
+ logwarn(msg);
+ }
+ public void verbose(String msg) {
+ loginfo(msg);
+ }
+ });
+ nWarn = bb.warnings().size();
+ if (!modified) {
+ msg = " (not modified)";
+ }
+ } catch (Exception e) {
+ List<String> errors = bb.errors();
+ if (errors != null) {
+ nErr = errors.size();
+ for (String err : errors) {
+ logerror(err);
+ }
+ }
+ throw SigilCore.newCoreException("Failed to create: " + id + ": " + e, e);
+ } finally {
+ loginfo(id + ": " + count(nErr, "error") + ", " + count(nWarn, "warning") + msg);
+ }
+ }
+ }
+
+ private static void loginfo(String message) {
+ BuildConsole console = findConsole();
+ MessageConsoleStream stream = console.getMessageStream();
+ stream.println("INFO: " + message);
+ }
+
+ private static void logwarn(String message) {
+ BuildConsole console = findConsole();
+ MessageConsoleStream stream = console.getMessageStream();
+ stream.println("WARN: " + message);
+ }
+
+ private static void logerror(String message) {
+ BuildConsole console = findConsole();
+ MessageConsoleStream stream = console.getMessageStream();
+ stream.println("ERROR: " + message);
+ }
+
+ private static BuildConsole findConsole() {
+ BuildConsole console = null;
+
+ IConsoleManager manager = ConsolePlugin.getDefault().getConsoleManager();
+
+ for ( IConsole c : manager.getConsoles() ) {
+ if ( c instanceof BuildConsole ) {
+ console = (BuildConsole) c;
+ break;
+ }
+ }
+
+ if ( console == null ) {
+ console = new BuildConsole();
+ manager.addConsoles( new IConsole[] { console } );
+ }
+
+ return console;
+ }
+
+ private String buildDestPattern(ISigilProjectModel sigil) throws CoreException {
+ IPath loc = sigil.findBundleLocation().removeLastSegments(1);
+
+ loc.toFile().mkdirs();
+
+ return loc.toOSString() + File.separator + "[name].jar";
+ }
+
+ private File[] buildClasspath(ISigilProjectModel sigil, IProgressMonitor monitor) throws CoreException {
+ ArrayList<File> files = new ArrayList<File>();
+
+ buildLocalClasspath(sigil, files);
+ buildExternalClasspath(sigil, files, monitor);
+
+ return files.toArray( new File[files.size()] );
+ }
+
+ private void buildExternalClasspath(ISigilProjectModel sigil,
+ ArrayList<File> files, IProgressMonitor monitor) throws CoreException {
+ Collection<IClasspathEntry> entries = sigil.findExternalClasspath(monitor);
+ files.ensureCapacity(files.size() + entries.size());
+
+ for ( IClasspathEntry cp : entries ) {
+ convert(cp, sigil, files);
+ }
+ }
+
+ private void buildLocalClasspath(ISigilProjectModel sigil, ArrayList<File> files) throws CoreException {
+ Collection<IClasspathEntry> entries = JavaHelper.findClasspathEntries(sigil.getBundle());
+ files.ensureCapacity(files.size() + entries.size());
+ for ( IClasspathEntry cp : entries ) {
+ convert(cp, sigil, files);
+ }
+
+ if ( !sigil.getBundle().getComposites().isEmpty() ) {
+ throw new IllegalStateException("XXX-FIXME-XXX");
+ }
+ }
+
+ private void convert(IClasspathEntry cp, ISigilProjectModel sigil, ArrayList<File> files) throws CoreException {
+ switch( cp.getEntryKind() ) {
+ case IClasspathEntry.CPE_PROJECT: {
+ IProject p = findProject(cp.getPath());
+ ISigilProjectModel project = SigilCore.create(p);
+ for ( String scp : project.getBundle().getClasspathEntrys() ) {
+ IClasspathEntry jcp = project.getJavaModel().decodeClasspathEntry(scp);
+ convert( jcp, project, files );
+ }
+ break;
+ }
+ case IClasspathEntry.CPE_SOURCE : {
+ IPath path = cp.getOutputLocation() == null ? sigil.getJavaModel().getOutputLocation() : cp.getOutputLocation();
+ IFolder buildFolder = sigil.getProject().getFolder(path.removeFirstSegments(1));
+ if ( buildFolder.exists() ) {
+ files.add(buildFolder.getLocation().toFile());
+ }
+ break;
+ }
+ case IClasspathEntry.CPE_LIBRARY: {
+ IPath p = cp.getPath();
+
+ IPath ppath = sigil.getProject().getFullPath();
+
+ if ( ppath.isPrefixOf(p) ) {
+ p = sigil.getProject().getLocation().append( p.removeFirstSegments(1) );
+ }
+
+ files.add( p.toFile() );
+ break;
+ }
+ case IClasspathEntry.CPE_VARIABLE:
+ cp = JavaCore.getResolvedClasspathEntry(cp);
+ if ( cp != null ) {
+ IPath p = cp.getPath();
+ files.add( p.toFile() );
+ }
+ break;
+ }
+ }
+
+ private IProject findProject(IPath path) throws CoreException {
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ for ( IProject p : root.getProjects() ) {
+ IPath projectPath = p.getFullPath();
+ if ( projectPath.equals( path ) ) {
+ return p;
+ }
+ }
+
+ throw SigilCore.newCoreException("No such project " + path, null);
+ }
+
+ private String count(int count, String msg) {
+ return count + " " + msg + (count == 1 ? "" : "s");
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/install/OSGiInstallManager.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/install/OSGiInstallManager.java
new file mode 100644
index 0000000..ce5f20f
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/install/OSGiInstallManager.java
@@ -0,0 +1,267 @@
+/*
+ * 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.cauldron.sigil.internal.install;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+import org.cauldron.sigil.SigilCore;
+import org.cauldron.sigil.install.IOSGiInstall;
+import org.cauldron.sigil.install.IOSGiInstallBuilder;
+import org.cauldron.sigil.install.IOSGiInstallManager;
+import org.cauldron.sigil.install.IOSGiInstallType;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialogWithToggle;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceDialog;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.PreferencesUtil;
+
+public class OSGiInstallManager implements IOSGiInstallManager, IPropertyChangeListener {
+ private static final int NORMAL_PRIORITY = 0;
+
+ private LinkedList<IOSGiInstallBuilder> builders = new LinkedList<IOSGiInstallBuilder>();
+
+ private HashMap<IPath, IOSGiInstall> pathToinstall = new HashMap<IPath, IOSGiInstall>();
+ private HashMap<String, IOSGiInstall> idToInstall = new HashMap<String, IOSGiInstall>();
+
+ private String defaultId;
+
+ private boolean initialised;
+
+ public IOSGiInstall findInstall(String id) {
+ init();
+ return idToInstall.get(id);
+ }
+
+ public String[] getInstallIDs() {
+ init();
+ return idToInstall.keySet().toArray( new String[idToInstall.size()] );
+ }
+
+ public IOSGiInstall[] getInstalls() {
+ init();
+ return idToInstall.values().toArray( new IOSGiInstall[idToInstall.size()] );
+ }
+
+ public IOSGiInstall getDefaultInstall() {
+ init();
+ return findInstall(defaultId);
+ }
+
+ public IOSGiInstallType findInstallType(String location) {
+ IOSGiInstallType type = null;
+
+ try {
+ IOSGiInstall install = buildInstall("tmp", new Path( location ) );
+ type = install == null ? null : install.getType();
+ } catch (CoreException e) {
+ SigilCore.error( "Failed to build install", e);
+ }
+
+ return type;
+ }
+
+ public void propertyChange(PropertyChangeEvent event) {
+ synchronized( this ) {
+ if ( event.getProperty().equals(SigilCore.OSGI_INSTALLS) ) {
+ clearInstalls();
+ String val = (String) event.getNewValue();
+ addInstalls(val);
+ }
+ else if ( event.getProperty().equals( SigilCore.OSGI_DEFAULT_INSTALL_ID ) ) {
+ defaultId = (String) event.getNewValue();
+ }
+ }
+ }
+
+ private void init() {
+ boolean show = false;
+
+ IPreferenceStore prefs = getPreferenceStore();
+
+ synchronized( this ) {
+ if ( !initialised ) {
+ initialised = true;
+
+ prefs.addPropertyChangeListener(this);
+
+ String val = prefs.getString(SigilCore.OSGI_INSTALLS);
+
+ boolean noAsk = prefs.getBoolean(SigilCore.PREFERENCES_NOASK_OSGI_INSTALL);
+ if(val == null || val.trim().length() == 0) {
+ show = !noAsk;
+ }
+ else {
+ addInstalls(val);
+ defaultId = prefs.getString(SigilCore.OSGI_DEFAULT_INSTALL_ID);
+ }
+ }
+ }
+
+ if ( show ) {
+ showInstallPrefs(prefs);
+ }
+ }
+
+ private void addInstalls(String prop) {
+ if ( prop != null && prop.trim().length() > 0 ) {
+ IPreferenceStore prefs = getPreferenceStore();
+
+ for (String id : prop.split(",")) {
+ String path = prefs.getString( SigilCore.OSGI_INSTALL_PREFIX + id );
+ addInstall(id, new Path( path ) );
+ }
+ }
+ }
+
+ private IPreferenceStore getPreferenceStore() {
+ return SigilCore.getDefault().getPreferenceStore();
+ }
+
+ private void showInstallPrefs(final IPreferenceStore prefs) {
+ Runnable r = new Runnable() {
+ public void run() {
+ MessageDialogWithToggle questionDialog = MessageDialogWithToggle.openYesNoQuestion(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), "Sigil Configuration", "Missing OSGi installation. Open preferences to configure it now?", "Do not show this message again", false, null, null);
+ prefs.setValue(SigilCore.PREFERENCES_NOASK_OSGI_INSTALL, questionDialog.getToggleState());
+ if(questionDialog.getReturnCode() == IDialogConstants.YES_ID) {
+ PreferenceDialog dialog = PreferencesUtil.createPreferenceDialogOn(null, SigilCore.OSGI_INSTALLS_PREFERENCES_ID, null, null);
+ dialog.open();
+ }
+ }
+ };
+ Display d = Display.getCurrent();
+ if ( d == null ) {
+ d = Display.getDefault();
+ d.asyncExec(r);
+ }
+ else {
+ d.syncExec(r);
+ }
+ }
+
+ private IOSGiInstall addInstall(String id, IPath path) {
+ IOSGiInstall install = pathToinstall.get(path);
+
+ if ( install == null ) {
+ try {
+ install = buildInstall(id, path);
+ if ( install != null ) {
+ pathToinstall.put( path, install );
+ idToInstall.put( install.getId(), install );
+ }
+ }
+ catch (CoreException e) {
+ SigilCore.error( "Failed to build install for " + path, e);
+ }
+ }
+
+ return install;
+ }
+
+ private IOSGiInstall buildInstall(String id, IPath path) throws CoreException {
+ initBuilders();
+ IOSGiInstall install = null;
+
+ for ( IOSGiInstallBuilder b : builders ) {
+ install = b.build(id, path);
+
+ if ( install != null ) {
+ break;
+ }
+ }
+
+ return install;
+ }
+
+ private void clearInstalls() {
+ idToInstall.clear();
+ pathToinstall.clear();
+ }
+
+ private void initBuilders() {
+ synchronized( builders ) {
+ if ( builders.isEmpty() ) {
+ final HashMap<IOSGiInstallBuilder, Integer> tmp = new HashMap<IOSGiInstallBuilder, Integer>();
+
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint p = registry.getExtensionPoint(SigilCore.INSTALL_BUILDER_EXTENSION_POINT_ID);
+ for ( IExtension e : p.getExtensions() ) {
+ for ( IConfigurationElement c : e.getConfigurationElements() ) {
+ createBuilderFromElement(c, tmp);
+ }
+ }
+
+ builders = new LinkedList<IOSGiInstallBuilder>(tmp.keySet());
+ Collections.sort(builders, new Comparator<IOSGiInstallBuilder>() {
+ public int compare(IOSGiInstallBuilder o1, IOSGiInstallBuilder o2) {
+ int p1 = tmp.get(o1);
+ int p2 = tmp.get(o2);
+
+ if ( p1 == p2 ) {
+ return 0;
+ }
+ else if ( p1 > p2 ) {
+ return -1;
+ }
+ else {
+ return 1;
+ }
+ }
+ });
+ }
+ }
+ }
+
+ private void createBuilderFromElement(IConfigurationElement c, Map<IOSGiInstallBuilder, Integer> builder) {
+ try {
+ IOSGiInstallBuilder b = (IOSGiInstallBuilder) c.createExecutableExtension("class");
+ int priority = parsePriority( c );
+ builder.put(b, priority);
+ } catch (CoreException e) {
+ SigilCore.error("Failed to create builder", e);
+ }
+ }
+
+ private int parsePriority(IConfigurationElement c) {
+ String str = c.getAttribute("priority");
+
+ if ( str == null ) {
+ return NORMAL_PRIORITY;
+ }
+ else {
+ return Integer.parseInt(str);
+ }
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/model/project/SigilModelRoot.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/model/project/SigilModelRoot.java
new file mode 100644
index 0000000..ea05121
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/model/project/SigilModelRoot.java
@@ -0,0 +1,126 @@
+/*
+ * 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.cauldron.sigil.internal.model.project;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+
+import org.cauldron.sigil.SigilCore;
+import org.cauldron.sigil.model.IModelElement;
+import org.cauldron.sigil.model.eclipse.ILibrary;
+import org.cauldron.sigil.model.eclipse.ILibraryImport;
+import org.cauldron.sigil.model.eclipse.ISigilBundle;
+import org.cauldron.sigil.model.osgi.IPackageExport;
+import org.cauldron.sigil.model.osgi.IPackageImport;
+import org.cauldron.sigil.model.osgi.IRequiredBundle;
+import org.cauldron.sigil.model.project.ISigilModelRoot;
+import org.cauldron.sigil.model.project.ISigilProjectModel;
+import org.cauldron.sigil.repository.IBundleResolver;
+import org.cauldron.sigil.repository.IResolution;
+import org.cauldron.sigil.repository.ResolutionConfig;
+import org.cauldron.sigil.repository.ResolutionException;
+import org.cauldron.sigil.repository.ResolutionMonitorAdapter;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+public class SigilModelRoot implements ISigilModelRoot {
+ public List<ISigilProjectModel> getProjects() {
+ IProject[] all = ResourcesPlugin.getWorkspace().getRoot().getProjects();
+ ArrayList<ISigilProjectModel> projects = new ArrayList<ISigilProjectModel>(all.length);
+ for (IProject p : all) {
+ try {
+ if (p.isOpen() && p.hasNature(SigilCore.NATURE_ID)) {
+ ISigilProjectModel n = SigilCore.create(p);
+ projects.add(n);
+ }
+ } catch (CoreException e) {
+ SigilCore.error("Failed to build model element", e);
+ }
+ }
+
+ return projects;
+ }
+
+ public Collection<ISigilProjectModel> resolveDependentProjects(
+ ISigilProjectModel sigil, IProgressMonitor monitor) {
+ HashSet<ISigilProjectModel> dependents = new HashSet<ISigilProjectModel>();
+
+ for (ISigilProjectModel n : getProjects()) {
+ if (!sigil.equals(n)) {
+ for (IPackageExport pe : sigil.getBundle().getBundleInfo().getExports()) {
+ for (IPackageImport i : n.getBundle().getBundleInfo()
+ .getImports()) {
+ if (pe.getPackageName().equals(i.getPackageName())
+ && i.getVersions().contains(pe.getVersion())) {
+ dependents.add(n);
+ }
+ }
+
+ for (ILibraryImport l : n.getBundle().getBundleInfo().getLibraryImports()) {
+ ILibrary lib = SigilCore.getRepositoryManager(sigil).resolveLibrary(l);
+
+ if (lib != null) {
+ for (IPackageImport i : lib.getImports()) {
+ if (pe.getPackageName().equals(
+ i.getPackageName())
+ && i.getVersions().contains(
+ pe.getVersion())) {
+ dependents.add(n);
+ }
+ }
+ } else {
+ SigilCore.error("No library found for " + l);
+ }
+ }
+ }
+
+ for (IRequiredBundle r : n.getBundle().getBundleInfo().getRequiredBundles()) {
+ if (sigil.getSymbolicName().equals(r.getSymbolicName())
+ && r.getVersions().contains(sigil.getVersion())) {
+ dependents.add(n);
+ }
+ }
+ }
+ }
+
+ return dependents;
+ }
+
+ public Collection<ISigilBundle> resolveBundles(ISigilProjectModel sigil, IModelElement element, boolean includeOptional, IProgressMonitor monitor) throws CoreException {
+ int options = ResolutionConfig.INCLUDE_DEPENDENTS;
+ if ( includeOptional ) {
+ options |= ResolutionConfig.INCLUDE_OPTIONAL;
+ }
+
+ ResolutionConfig config = new ResolutionConfig(options);
+ try {
+ IBundleResolver resolver = SigilCore.getRepositoryManager(sigil).getBundleResolver();
+ IResolution resolution = resolver.resolve(element, config, new ResolutionMonitorAdapter(monitor));
+ resolution.synchronize(monitor);
+ return resolution.getBundles();
+ } catch (ResolutionException e) {
+ throw SigilCore.newCoreException(e.getMessage(), e);
+ }
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/model/project/SigilProject.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/model/project/SigilProject.java
new file mode 100644
index 0000000..7a7f3af
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/model/project/SigilProject.java
@@ -0,0 +1,460 @@
+/*
+ * 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.cauldron.sigil.internal.model.project;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.cauldron.bld.config.BldFactory;
+import org.cauldron.bld.config.IBldProject;
+import org.cauldron.sigil.SigilCore;
+import org.cauldron.sigil.job.ThreadProgressMonitor;
+import org.cauldron.sigil.model.AbstractCompoundModelElement;
+import org.cauldron.sigil.model.IModelElement;
+import org.cauldron.sigil.model.IModelWalker;
+import org.cauldron.sigil.model.ModelElementFactory;
+import org.cauldron.sigil.model.eclipse.ISigilBundle;
+import org.cauldron.sigil.model.osgi.IBundleModelElement;
+import org.cauldron.sigil.model.osgi.IPackageExport;
+import org.cauldron.sigil.model.osgi.IPackageImport;
+import org.cauldron.sigil.model.osgi.IRequiredBundle;
+import org.cauldron.sigil.model.project.ISigilProjectModel;
+import org.cauldron.sigil.model.util.JavaHelper;
+import org.cauldron.sigil.repository.IRepositoryManager;
+import org.cauldron.sigil.repository.IResolution;
+import org.cauldron.sigil.repository.ResolutionConfig;
+import org.cauldron.sigil.repository.ResolutionException;
+import org.cauldron.sigil.repository.ResolutionMonitorAdapter;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ProjectScope;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener;
+import org.eclipse.jdt.core.ClasspathContainerInitializer;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.IParent;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+import org.osgi.framework.Version;
+import org.osgi.service.prefs.Preferences;
+
+/**
+ * @author dave
+ *
+ */
+public class SigilProject extends AbstractCompoundModelElement implements ISigilProjectModel {
+
+ private static final long serialVersionUID = 1L;
+
+ private IFile bldProjectFile;
+ private IProject project;
+ private IBldProject bldProject;
+
+ private ISigilBundle bundle;
+
+ private IEclipsePreferences preferences;
+
+ public SigilProject() {
+ super( "Sigil Project" );
+ }
+
+ public SigilProject(IProject project) throws CoreException {
+ this();
+ this.project = project;
+ bldProjectFile = project.getFile( new Path( SigilCore.SIGIL_PROJECT_FILE) );
+ }
+
+ // to aid testing conversion between project file formats
+ public InputStream saveBundle(ISigilBundle b) throws CoreException {
+ setBundle(b);
+ // FIXME causes NPE in JavaHelper
+ // calculateUses();
+ return buildContents();
+ }
+
+ public void save(IProgressMonitor monitor) throws CoreException {
+ SubMonitor progress = SubMonitor.convert(monitor, 100);
+
+ calculateUses();
+
+ bldProjectFile.setContents( buildContents(), IFile.KEEP_HISTORY, progress.newChild(10));
+
+ IRepositoryManager manager = SigilCore.getRepositoryManager(this);
+ ResolutionConfig config = new ResolutionConfig(ResolutionConfig.INCLUDE_OPTIONAL);
+
+ try {
+ IResolution res = manager.getBundleResolver().resolve(this, config, new ResolutionMonitorAdapter(progress.newChild(10)));
+ if ( !res.isSynchronized() ) {
+ res.synchronize(progress.newChild(60));
+ }
+ } catch (ResolutionException e) {
+ throw SigilCore.newCoreException("Failed to synchronize dependencies", e);
+ }
+
+
+ progress.setWorkRemaining(40);
+
+ SigilCore.rebuildBundleDependencies( this, progress.newChild(20) );
+ }
+
+ /**
+ * Returns the project custom preference pool.
+ * Project preferences may include custom encoding.
+ * @return IEclipsePreferences or <code>null</code> if the project
+ * does not have a java nature.
+ */
+ public Preferences getPreferences(){
+ synchronized(this) {
+ if ( preferences == null ) {
+ preferences = loadPreferences();
+ }
+
+ return preferences;
+ }
+ }
+
+
+ /**
+ * @return
+ */
+ private synchronized IEclipsePreferences loadPreferences() {
+ IScopeContext context = new ProjectScope(getProject());
+ final IEclipsePreferences eclipsePreferences = context.getNode(SigilCore.PLUGIN_ID);
+
+ // Listen to node removal from parent in order to reset cache
+ INodeChangeListener nodeListener = new IEclipsePreferences.INodeChangeListener() {
+ public void added(IEclipsePreferences.NodeChangeEvent event) {
+ // do nothing
+ }
+
+ public void removed(IEclipsePreferences.NodeChangeEvent event) {
+ if (event.getChild() == eclipsePreferences) {
+ synchronized( SigilProject.this ) {
+ preferences = null;
+ }
+ ((IEclipsePreferences) eclipsePreferences.parent()).removeNodeChangeListener(this);
+ }
+ }
+ };
+
+ ((IEclipsePreferences) eclipsePreferences.parent()).addNodeChangeListener(nodeListener);
+
+ return eclipsePreferences;
+ }
+
+ public Collection<IClasspathEntry> findExternalClasspath(IProgressMonitor monitor) throws CoreException {
+ return JavaHelper.resolveClasspathEntrys(this, monitor);
+ }
+
+ private void calculateUses() {
+ visit( new IModelWalker() {
+ public boolean visit(IModelElement element) {
+ if ( element instanceof IPackageExport ) {
+ IPackageExport pe = (IPackageExport) element;
+ try {
+ pe.setUses( Arrays.asList( JavaHelper.findUses(pe.getPackageName(), SigilProject.this ) ) );
+ } catch (CoreException e) {
+ SigilCore.error( "Failed to build uses list for " + pe, e );
+ }
+ }
+ return true;
+ }
+ } );
+ }
+
+ public Collection<ISigilProjectModel> findDependentProjects(IProgressMonitor monitor) {
+ return SigilCore.getRoot().resolveDependentProjects(this, monitor);
+ }
+
+ public Version getVersion() {
+ ISigilBundle bundle = getBundle();
+ return bundle == null ? null : bundle.getBundleInfo() == null ? null : bundle.getBundleInfo().getVersion();
+ }
+
+ public String getSymbolicName() {
+ ISigilBundle bundle = getBundle();
+ return bundle == null ? null : bundle.getBundleInfo() == null ? null : bundle.getBundleInfo().getSymbolicName();
+ }
+
+ public IProject getProject() {
+ return project;
+ }
+
+ public ISigilBundle getBundle() {
+ if ( bundle == null && bldProjectFile != null ) {
+ synchronized( bldProjectFile ) {
+ try {
+ if ( bldProjectFile.getLocation().toFile().exists() ) {
+ bundle = parseContents(bldProjectFile);
+ }
+ else {
+ bundle = setupDefaults();
+ NullProgressMonitor npm = new NullProgressMonitor();
+ bldProjectFile.create( buildContents(), true /* force */, npm);
+ project.refreshLocal( IResource.DEPTH_INFINITE, npm );
+ }
+ } catch (CoreException e) {
+ SigilCore.error( "Failed to build bundle", e);
+ }
+ }
+ }
+ return bundle;
+ }
+
+ public void setBundle(ISigilBundle bundle) {
+ this.bundle = bundle;
+ }
+
+ public IJavaProject getJavaModel() {
+ return JavaCore.create( project );
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if ( obj == null ) return false;
+
+ if ( obj == this ) return true;
+
+ try {
+ SigilProject p = (SigilProject) obj;
+ return getSymbolicName().equals( p.getSymbolicName() ) && (getVersion() == null ? p.getVersion() == null : getVersion().equals( p.getVersion() ));
+ }
+ catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ // TODO Auto-generated method stub
+ return super.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "SigilProject[" + getSymbolicName() + ":" + getVersion() + "]";
+ }
+
+ public void resetClasspath(IProgressMonitor monitor) throws CoreException {
+ Path containerPath = new Path( SigilCore.CLASSPATH_CONTAINER_PATH );
+ IJavaProject java = getJavaModel();
+ ClasspathContainerInitializer init = JavaCore.getClasspathContainerInitializer(SigilCore.CLASSPATH_CONTAINER_PATH);
+ ThreadProgressMonitor.setProgressMonitor(monitor);
+ try {
+ init.requestClasspathContainerUpdate(containerPath, java, null);
+ }
+ finally {
+ ThreadProgressMonitor.setProgressMonitor(null);
+ }
+ }
+
+ public IPath findBundleLocation() throws CoreException {
+ IPath p = getBundle().getLocation();
+ if ( p == null ) {
+ p = SigilCore.getDefault().findDefaultBundleLocation(this);
+ }
+ return p;
+ }
+
+ public IModelElement findImport(final String packageName, final IProgressMonitor monitor) {
+ final IModelElement[] found = new IModelElement[1];
+
+ visit( new IModelWalker() {
+ public boolean visit(IModelElement element) {
+ if ( element instanceof IPackageImport ) {
+ IPackageImport pi = (IPackageImport) element;
+ if ( pi.getPackageName().equals( packageName ) ) {
+ found[0] = pi;
+ return false;
+ }
+ }
+ else if ( element instanceof IRequiredBundle ) {
+ IRequiredBundle rb = (IRequiredBundle) element;
+ try {
+ IRepositoryManager manager = SigilCore.getRepositoryManager(SigilProject.this);
+ ResolutionConfig config = new ResolutionConfig(ResolutionConfig.IGNORE_ERRORS);
+ IResolution res = manager.getBundleResolver().resolve(rb, config, new ResolutionMonitorAdapter(monitor));
+ ISigilBundle b = res.getProvider(rb);
+ for ( IPackageExport pe : b.getBundleInfo().getExports() ) {
+ if ( pe.getPackageName().equals( packageName ) ) {
+ found[0] = rb;
+ return false;
+ }
+ }
+ } catch (ResolutionException e) {
+ SigilCore.error( "Failed to resolve " + rb, e );
+ }
+ }
+ return true;
+ }
+
+ });
+
+ return found[0];
+ }
+
+ public boolean isInClasspath(String packageName, IProgressMonitor monitor) throws CoreException {
+ if ( findImport(packageName, monitor) != null ) {
+ return true;
+ }
+
+ for ( String path : getBundle().getClasspathEntrys() ) {
+ IClasspathEntry cp = getJavaModel().decodeClasspathEntry(path);
+ for ( IPackageFragmentRoot root : getJavaModel().findPackageFragmentRoots(cp) ) {
+ if ( findPackage( packageName, root ) ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean isInClasspath(ISigilBundle bundle) {
+ for ( String path : getBundle().getClasspathEntrys() ) {
+ IClasspathEntry cp = getJavaModel().decodeClasspathEntry(path);
+ switch ( cp.getEntryKind() ) {
+ case IClasspathEntry.CPE_PROJECT:
+ ISigilProjectModel p = bundle.getAncestor(ISigilProjectModel.class);
+ return p != null && cp.getPath().equals(p.getProject().getFullPath());
+ case IClasspathEntry.CPE_LIBRARY:
+ return cp.getPath().equals(bundle.getLocation());
+ }
+ }
+
+ return false;
+ }
+
+ private boolean findPackage(String packageName, IParent parent) throws JavaModelException {
+ for ( IJavaElement e : parent.getChildren() ) {
+ if ( e.getElementType() == IJavaElement.PACKAGE_FRAGMENT ) {
+ return e.getElementName().equals( packageName );
+ }
+
+ if ( e instanceof IParent ) {
+ if ( findPackage(packageName, (IParent) e) ) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private ISigilBundle setupDefaults() {
+ ISigilBundle bundle = ModelElementFactory.getInstance().newModelElement(ISigilBundle.class);
+ IBundleModelElement info = ModelElementFactory.getInstance().newModelElement( IBundleModelElement.class );
+ info.setSymbolicName(project.getName());
+ bundle.setBundleInfo(info);
+ bundle.setParent(this);
+ return bundle;
+ }
+
+
+ private ISigilBundle parseContents(IFile projectFile) throws CoreException {
+ /*if ( !projectFile.isSynchronized(IResource.DEPTH_ONE) ) {
+ projectFile.refreshLocal(IResource.DEPTH_ONE, new NullProgressMonitor());
+ }*/
+
+ if ( projectFile.getName().equals( SigilCore.SIGIL_PROJECT_FILE) ) {
+ return parseBldContents(projectFile.getLocationURI());
+ }
+ else {
+ throw SigilCore.newCoreException("Unexpected project file: " + projectFile.getName(), null );
+ }
+ }
+
+ private ISigilBundle parseBldContents(URI uri) throws CoreException {
+ try {
+ bldProject = BldFactory.getProject(uri, true);
+ ISigilBundle bundle = bldProject.getDefaultBundle();
+ bundle.setParent(this);
+ return bundle;
+ } catch (IOException e) {
+ throw SigilCore.newCoreException( "Failed to parse " + uri, e);
+ }
+ }
+
+ private InputStream buildContents() throws CoreException {
+ ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ try {
+ if (bldProject == null) {
+ bldProject = BldFactory.newProject(bldProjectFile.getLocationURI(), null);
+ }
+ bldProject.setDefaultBundle(getBundle());
+ bldProject.saveTo(buf);
+ } catch (IOException e) {
+ throw SigilCore.newCoreException("Failed to save project file", e);
+ }
+ return new ByteArrayInputStream(buf.toByteArray());
+ }
+
+// private InputStream buildXMLContents() throws CoreException {
+// Serializer serializer = SigilCore.getDefault().getDescriptorSerializer();
+//
+// ByteArrayOutputStream buf = new ByteArrayOutputStream();
+//
+// try {
+// serializer.serialize(getBundle(), buf);
+// } catch (SerializingException e) {
+// throw SigilCore.newCoreException("Failed to serialize " + this, e);
+// }
+//
+// return new ByteArrayInputStream(buf.toByteArray());
+// }
+
+ public String getName() {
+ return getProject().getName();
+ }
+
+ public IPath findOutputLocation() throws CoreException {
+ return getProject().getLocation().append(
+ getJavaModel().getOutputLocation()
+ .removeFirstSegments(1));
+ }
+
+ public IBldProject getBldProject() throws CoreException {
+ try {
+ return BldFactory.getProject(project.getFile(IBldProject.PROJECT_FILE).getLocationURI());
+ } catch (IOException e) {
+ throw SigilCore.newCoreException("Failed to get project file: ",e);
+ }
+ }
+
+ public boolean isInBundleClasspath(IPackageFragmentRoot root) throws JavaModelException {
+ String enc = getJavaModel().encodeClasspathEntry(root.getRawClasspathEntry());
+ return getBundle().getClasspathEntrys().contains( enc.trim() );
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/model/repository/RepositoryConfiguration.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/model/repository/RepositoryConfiguration.java
new file mode 100644
index 0000000..592e75b
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/model/repository/RepositoryConfiguration.java
@@ -0,0 +1,395 @@
+/*
+ * 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.cauldron.sigil.internal.model.repository;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.cauldron.sigil.SigilCore;
+import org.cauldron.sigil.model.repository.IRepositoryConfiguration;
+import org.cauldron.sigil.model.repository.IRepositoryModel;
+import org.cauldron.sigil.model.repository.IRepositorySet;
+import org.cauldron.sigil.model.repository.IRepositoryType;
+import org.cauldron.sigil.model.repository.RepositorySet;
+import org.cauldron.sigil.preferences.PrefsUtils;
+import org.cauldron.sigil.repository.IBundleRepository;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceStore;
+import org.eclipse.swt.graphics.Image;
+import org.osgi.framework.Bundle;
+
+public class RepositoryConfiguration implements IRepositoryConfiguration {
+
+ private static final String REPOSITORY = "repository.";
+ private static final String REPOSITORY_SET = REPOSITORY + "set.";
+ private static final String REPOSITORY_SETS = REPOSITORY + "sets";
+ private static final String REPOSITORY_TIMESTAMP = REPOSITORY + "timestamp";
+ private static final String INSTANCES = ".instances";
+ private static final String NAME = ".name";
+ private static final String LOC = ".loc";
+ private static final String TIMESTAMP = ".timestamp";
+
+ public static final String REPOSITORY_DEFAULT_SET = REPOSITORY + "default.set";
+
+ /* (non-Javadoc)
+ * @see org.cauldron.sigil.repository.management.IRepositoryManagement#loadRepositories()
+ */
+ public List<IRepositoryModel> loadRepositories() {
+ IPreferenceStore prefs = SigilCore.getDefault().getPreferenceStore();
+
+ ArrayList<IRepositoryModel> repositories = new ArrayList<IRepositoryModel>();
+
+ for ( RepositoryType type : loadRepositoryTypes() ) {
+ String typeID = type.getId();
+
+ if ( type.isDynamic() ) {
+ String instances = prefs.getString( REPOSITORY + typeID + INSTANCES );
+ if ( instances.trim().length() > 0 ) {
+ for( String instance : instances.split(",") ) {
+ String key = REPOSITORY + typeID + "." + instance;
+ repositories.add( loadRepository(instance, key, type, prefs) );
+ }
+ }
+ }
+ else {
+ String key = REPOSITORY + typeID;
+ repositories.add( loadRepository(typeID, key, type, prefs) );
+ }
+
+ }
+
+ return repositories;
+ }
+
+ public IRepositoryModel findRepository(String id) {
+ for (IRepositoryModel model : loadRepositories()) {
+ if ( model.getId().equals( id ) ) {
+ return model;
+ }
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.cauldron.sigil.repository.management.IRepositoryManagement#saveRepositories(java.util.List)
+ */
+ public void saveRepositories(List<IRepositoryModel> repositories) throws CoreException {
+ IPreferenceStore prefs = getPreferences();
+
+ HashMap<IRepositoryType, List<IRepositoryModel>> mapped = new HashMap<IRepositoryType, List<IRepositoryModel>>(repositories.size());
+
+ saveRepositoryPreferences(repositories, mapped);
+ createNewEntries(mapped, prefs);
+ deleteOldEntries(repositories,prefs);
+ // time stamp is used as a signal to the manager
+ // to update its view of the stored repositories
+ timeStamp(prefs);
+ }
+
+ /* (non-Javadoc)
+ * @see org.cauldron.sigil.repository.management.IRepositoryManagement#loadRepositoryTypes()
+ */
+ public List<RepositoryType> loadRepositoryTypes() {
+ List<RepositoryType> repositories = new ArrayList<RepositoryType>();
+
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+
+ IExtensionPoint p = registry.getExtensionPoint(SigilCore.REPOSITORY_PROVIDER_EXTENSION_POINT_ID);
+
+ for ( IExtension e : p.getExtensions() ) {
+ for ( IConfigurationElement c : e.getConfigurationElements() ) {
+ String id = c.getAttribute("id");
+ String type = c.getAttribute("type");
+ boolean dynamic = Boolean.valueOf( c.getAttribute("dynamic") );
+ String icon = c.getAttribute("icon");
+ Image image = (icon == null || icon.trim().length() == 0) ? null : loadImage(e, icon);
+ repositories.add( new RepositoryType(id, type, dynamic, image ) );
+ }
+ }
+
+ return repositories;
+ }
+
+ /* (non-Javadoc)
+ * @see org.cauldron.sigil.repository.management.IRepositoryManagement#newRepositoryElement(org.cauldron.sigil.repository.management.RepositoryType)
+ */
+ public IRepositoryModel newRepositoryElement(IRepositoryType type) {
+ String id = UUID.randomUUID().toString();
+ PreferenceStore prefs = new PreferenceStore();
+ RepositoryModel element = new RepositoryModel(id, "", type, prefs);
+ prefs.setFilename(makeFileName(element));
+ prefs.setValue("id", id);
+ return element;
+ }
+
+ public IRepositorySet getDefaultRepositorySet() {
+ //int level = findLevel( key + LEVEL, type, prefs );
+ ArrayList<IRepositoryModel> reps = new ArrayList<IRepositoryModel>();
+ for ( String s : PrefsUtils.stringToArray(getPreferences().getString( REPOSITORY_DEFAULT_SET)) ) {
+ reps.add( findRepository(s) );
+ }
+ return new RepositorySet( reps );
+ }
+
+ public IRepositorySet getRepositorySet(String name) {
+ String key = REPOSITORY_SET + name;
+ if ( getPreferences().contains(key) ) {
+ ArrayList<IRepositoryModel> reps = new ArrayList<IRepositoryModel>();
+ for ( String s : PrefsUtils.stringToArray(getPreferences().getString( key )) ) {
+ reps.add( findRepository(s) );
+ }
+ return new RepositorySet( reps );
+ }
+ else {
+ return null;
+ }
+ }
+
+ public Map<String, IRepositorySet> loadRepositorySets() {
+ IPreferenceStore store = getPreferences();
+
+ HashMap<String, IRepositorySet> sets = new HashMap<String, IRepositorySet>();
+
+ for ( String name : PrefsUtils.stringToArray(store.getString(REPOSITORY_SETS))) {
+ String key = REPOSITORY_SET + name;
+ ArrayList<IRepositoryModel> reps = new ArrayList<IRepositoryModel>();
+ for ( String s : PrefsUtils.stringToArray(getPreferences().getString( key )) ) {
+ reps.add( findRepository(s) );
+ }
+ sets.put( name, new RepositorySet( reps ) );
+ }
+
+ return sets;
+ }
+
+ public void saveRepositorySets(Map<String, IRepositorySet> sets) {
+ IPreferenceStore store = getPreferences();
+
+ ArrayList<String> names = new ArrayList<String>();
+
+ for ( Map.Entry<String, IRepositorySet> set : sets.entrySet() ) {
+ String name = set.getKey();
+ String key = REPOSITORY_SET + name;
+ ArrayList<String> ids = new ArrayList<String>();
+ for ( IRepositoryModel m : set.getValue().getRepositories() ) {
+ ids.add( m.getId() );
+ }
+ store.setValue(key, PrefsUtils.listToString(ids) );
+ names.add( name );
+ }
+
+ for ( String name : PrefsUtils.stringToArray(store.getString(REPOSITORY_SETS))) {
+ if ( !names.contains(name) ) {
+ String key = REPOSITORY_SET + name;
+ store.setToDefault(key);
+ }
+ }
+
+ store.setValue(REPOSITORY_SETS, PrefsUtils.listToString(names) );
+ timeStamp(store);
+ }
+
+ public void setDefaultRepositorySet(IRepositorySet defaultSet) {
+ ArrayList<String> ids = new ArrayList<String>();
+ for ( IRepositoryModel m : defaultSet.getRepositories() ) {
+ ids.add( m.getId() );
+ }
+ IPreferenceStore prefs = getPreferences();
+ prefs.setValue( REPOSITORY_DEFAULT_SET, PrefsUtils.listToString( ids ) );
+ timeStamp(prefs);
+ }
+
+ private void timeStamp(IPreferenceStore prefs) {
+ prefs.setValue( REPOSITORY_TIMESTAMP, System.currentTimeMillis() );
+ }
+
+ private IPreferenceStore getPreferences() {
+ return SigilCore.getDefault().getPreferenceStore();
+ }
+
+ private void deleteOldEntries(List<IRepositoryModel> repositories, IPreferenceStore prefs) {
+ for ( IRepositoryModel e : loadRepositories() ) {
+ if ( !repositories.contains(e) ) {
+ new File( makeFileName(e) ).delete();
+ String key = makeKey(e);
+ prefs.setToDefault( key + LOC );
+ prefs.setToDefault( key + NAME );
+ }
+ }
+
+ for ( IRepositoryType type : loadRepositoryTypes() ) {
+ boolean found = false;
+ for ( IRepositoryModel e : repositories ) {
+ if ( e.getType().equals( type ) ) {
+ found = true;
+ break;
+ }
+ }
+
+ if ( !found ) {
+ prefs.setToDefault( REPOSITORY + type.getId() + INSTANCES );
+ }
+ }
+ }
+
+ private static void createNewEntries(HashMap<IRepositoryType, List<IRepositoryModel>> mapped, IPreferenceStore prefs) {
+ for ( Map.Entry<IRepositoryType, List<IRepositoryModel>> entry : mapped.entrySet() ) {
+ IRepositoryType type = entry.getKey();
+ if ( type.isDynamic() ) {
+ StringBuffer buf = new StringBuffer();
+
+ for ( IRepositoryModel element : entry.getValue() ) {
+ if ( buf.length() > 0 ) {
+ buf.append( "," );
+ }
+ buf.append( element.getId() );
+ saveRepository(element, prefs);
+ }
+
+ prefs.setValue( REPOSITORY + type.getId() + INSTANCES, buf.toString() );
+ }
+ else {
+ IRepositoryModel element = entry.getValue().get(0);
+ saveRepository(element, prefs);
+ }
+ }
+ }
+
+ private static void saveRepositoryPreferences(List<IRepositoryModel> repositories,
+ HashMap<IRepositoryType, List<IRepositoryModel>> mapped) throws CoreException {
+ for( IRepositoryModel rep : repositories ) {
+ try {
+ createDir( makeFileName(rep));
+ rep.getPreferences().save();
+ List<IRepositoryModel> list = mapped.get( rep.getType() );
+ if ( list == null ) {
+ list = new ArrayList<IRepositoryModel>(1);
+ mapped.put( rep.getType(), list );
+ }
+ list.add( rep );
+ } catch (IOException e) {
+ throw SigilCore.newCoreException("Failed to save repository preferences", e);
+ }
+ }
+ }
+
+ private static void createDir(String fileName) {
+ File file = new File( fileName );
+ file.getParentFile().mkdirs();
+ }
+
+ private static void saveRepository(IRepositoryModel element, IPreferenceStore prefs) {
+ String key = makeKey(element);
+ prefs.setValue( key + LOC, makeFileName(element) );
+ if ( element.getType().isDynamic() ) {
+ prefs.setValue( key + NAME, element.getName() );
+ }
+ prefs.setValue( key + TIMESTAMP, now() );
+ }
+
+ private static long now() {
+ return System.currentTimeMillis();
+ }
+
+ private static String makeKey(IRepositoryModel element) {
+ IRepositoryType type = element.getType();
+
+ String key = REPOSITORY + type.getId();
+ if ( type.isDynamic() )
+ key = key + "." + element.getId();
+
+ return key;
+ }
+
+ private static String makeFileName(IRepositoryModel element) {
+ IPath path = SigilCore.getDefault().getStateLocation();
+ path = path.append( "repository" );
+ path = path.append( element.getType().getId() );
+ path = path.append( element.getId() );
+ return path.toOSString();
+ }
+
+ private static RepositoryModel loadRepository(String id, String key, RepositoryType type, IPreferenceStore prefs) {
+ String name = type.isDynamic() ? prefs.getString( key + NAME ) : type.getType();
+
+ PreferenceStore repPrefs = new PreferenceStore();
+ RepositoryModel element = new RepositoryModel( id, name, type, repPrefs );
+
+ String loc = prefs.getString( key + LOC );
+
+ if ( loc == null || loc.trim().length() == 0 ) {
+ loc = makeFileName(element);
+ }
+
+ repPrefs.setFilename(loc);
+
+ if ( new File( loc ).exists() ) {
+ try {
+ repPrefs.load();
+ } catch (IOException e) {
+ SigilCore.error("Failed to load properties for repository " + key, e );
+ }
+ }
+
+ repPrefs.setValue( "id", id );
+
+ return element;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Image loadImage(IExtension ext, String icon) {
+ int i = icon.lastIndexOf( "/" );
+ String path = i == -1 ? "/" : icon.substring(0, i);
+ String name = i == -1 ? icon : icon.substring(i+1);
+
+ Bundle b = Platform.getBundle(ext.getContributor().getName());
+
+ Enumeration<URL> en = b.findEntries(path, name, false);
+ Image image = null;
+
+ if ( en.hasMoreElements() ) {
+ try {
+ image = SigilCore.loadImage(en.nextElement());
+ } catch (IOException e) {
+ SigilCore.error( "Failed to load image", e );
+ }
+ }
+ else {
+ SigilCore.error("No such image " + icon + " in bundle " + b.getSymbolicName() );
+ }
+
+ return image;
+ }
+
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/model/repository/RepositoryModel.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/model/repository/RepositoryModel.java
new file mode 100644
index 0000000..9b72541
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/model/repository/RepositoryModel.java
@@ -0,0 +1,96 @@
+/*
+ * 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.cauldron.sigil.internal.model.repository;
+
+import org.cauldron.sigil.model.repository.IRepositoryModel;
+import org.cauldron.sigil.model.repository.IRepositoryType;
+import org.eclipse.jface.preference.PreferenceStore;
+
+public class RepositoryModel implements IRepositoryModel {
+ private String id;
+
+ private String name;
+
+ private IRepositoryType type;
+
+ private PreferenceStore preferences;
+
+ public RepositoryModel(String id, String name, IRepositoryType type, PreferenceStore preferences) {
+ this.id = id;
+ this.name = name;
+ this.type = type;
+ this.preferences = preferences;
+ }
+
+ /* (non-Javadoc)
+ * @see org.cauldron.sigil.ui.preferences.repository.IRepositoryModel#getPreferences()
+ */
+ public PreferenceStore getPreferences() {
+ return preferences;
+ }
+
+ /* (non-Javadoc)
+ * @see org.cauldron.sigil.ui.preferences.repository.IRepositoryModel#getType()
+ */
+ public IRepositoryType getType() {
+ return type;
+ }
+
+ /* (non-Javadoc)
+ * @see org.cauldron.sigil.ui.preferences.repository.IRepositoryModel#getId()
+ */
+ public String getId() {
+ return id;
+ }
+
+ /* (non-Javadoc)
+ * @see org.cauldron.sigil.ui.preferences.repository.IRepositoryModel#getName()
+ */
+ public String getName() {
+ return name;
+ }
+
+ /* (non-Javadoc)
+ * @see org.cauldron.sigil.ui.wizard.repository.IRepositoryModel#setName(java.lang.String)
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ try {
+ RepositoryModel e = (RepositoryModel) obj;
+ return id.equals(e.id);
+ }
+ catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ public String toString() {
+ return type.getId() + ":" + id + ":" + name;
+ }
+}
\ No newline at end of file
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/model/repository/RepositoryType.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/model/repository/RepositoryType.java
new file mode 100644
index 0000000..30525a4
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/model/repository/RepositoryType.java
@@ -0,0 +1,87 @@
+/*
+ * 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.cauldron.sigil.internal.model.repository;
+
+import org.cauldron.sigil.model.repository.IRepositoryType;
+import org.eclipse.swt.graphics.Image;
+
+public class RepositoryType implements IRepositoryType {
+ private String type;
+ private String id;
+ private Image icon;
+ private boolean dynamic;
+
+ public RepositoryType(String id, String type, boolean dynamic,
+ Image icon) {
+ this.id = id;
+ this.type = type;
+ this.dynamic = dynamic;
+ this.icon = icon;
+ }
+
+ /* (non-Javadoc)
+ * @see org.cauldron.sigil.ui.preferences.repository.IRepositoryType#getType()
+ */
+ public String getType() {
+ return type;
+ }
+
+ /* (non-Javadoc)
+ * @see org.cauldron.sigil.ui.preferences.repository.IRepositoryType#getId()
+ */
+ public String getId() {
+ return id;
+ }
+
+ /* (non-Javadoc)
+ * @see org.cauldron.sigil.ui.preferences.repository.IRepositoryType#getIcon()
+ */
+ public Image getIcon() {
+ return icon;
+ }
+
+ /* (non-Javadoc)
+ * @see org.cauldron.sigil.ui.preferences.repository.IRepositoryType#isDynamic()
+ */
+ public boolean isDynamic() {
+ return dynamic;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ try {
+ RepositoryType t = (RepositoryType) obj;
+ return t.id.equals( id );
+ }
+ catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return type;
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/repository/eclipse/GlobalRepositoryManager.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/repository/eclipse/GlobalRepositoryManager.java
new file mode 100644
index 0000000..c974644
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/repository/eclipse/GlobalRepositoryManager.java
@@ -0,0 +1,42 @@
+/*
+ * 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.cauldron.sigil.internal.repository.eclipse;
+
+import java.util.List;
+
+import org.cauldron.sigil.SigilCore;
+import org.cauldron.sigil.internal.repository.eclipse.SigilRepositoryManager;
+import org.cauldron.sigil.model.repository.IRepositoryModel;
+import org.cauldron.sigil.repository.IRepositoryManager;
+
+public class GlobalRepositoryManager extends SigilRepositoryManager implements
+ IRepositoryManager {
+
+ public GlobalRepositoryManager() {
+ super(null);
+ }
+
+ @Override
+ protected IRepositoryModel[] findRepositories() {
+ List<IRepositoryModel> repos = SigilCore.getRepositoryConfiguration().loadRepositories();
+ return repos.toArray( new IRepositoryModel[repos.size()]);
+ }
+
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/repository/eclipse/OSGiInstallRepository.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/repository/eclipse/OSGiInstallRepository.java
new file mode 100644
index 0000000..186e962
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/repository/eclipse/OSGiInstallRepository.java
@@ -0,0 +1,135 @@
+/*
+ * 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.cauldron.sigil.internal.repository.eclipse;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+import org.cauldron.bld.core.BldCore;
+import org.cauldron.sigil.SigilCore;
+import org.cauldron.sigil.install.IOSGiInstall;
+import org.cauldron.sigil.model.ModelElementFactory;
+import org.cauldron.sigil.model.ModelElementFactoryException;
+import org.cauldron.sigil.model.eclipse.ISigilBundle;
+import org.cauldron.sigil.model.osgi.IBundleModelElement;
+import org.cauldron.sigil.repository.AbstractBundleRepository;
+import org.cauldron.sigil.repository.IRepositoryVisitor;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+
+public class OSGiInstallRepository extends AbstractBundleRepository {
+
+ private Map<String,List<ISigilBundle>> bundles;
+
+ public OSGiInstallRepository(String id) {
+ super(id);
+ }
+
+ public void refresh() {
+ synchronized( this ) {
+ bundles = null;
+ }
+
+ notifyChange();
+ }
+
+ @Override
+ public void accept(IRepositoryVisitor visitor, int options) {
+ IOSGiInstall install = SigilCore.getInstallManager().getDefaultInstall();
+
+ if ( install != null ) {
+ List<ISigilBundle> found = null;
+
+ synchronized( this ) {
+ found = bundles == null ? null : bundles.get( install.getId() );
+ }
+
+ if ( found == null ) {
+ found = new ArrayList<ISigilBundle>();
+ IPath source = install.getType().getSourceLocation();
+
+ for ( IPath p : install.getType().getDefaultBundleLocations() ) {
+ loadBundle( p, found, source );
+ }
+
+ synchronized( this ) {
+ bundles = new HashMap<String, List<ISigilBundle>>();
+ bundles.put( install.getId(), found );
+ }
+ }
+
+ for ( ISigilBundle b : found ) {
+ if ( !visitor.visit(b) ) {
+ break;
+ }
+ }
+ }
+ }
+
+ private void loadBundle(IPath p, List<ISigilBundle> bundles, IPath source) {
+ File f = p.toFile();
+ JarFile jar = null;
+ try {
+ jar = new JarFile(f);
+ ISigilBundle bundle = buildBundle(jar.getManifest(), f );
+ if ( bundle != null ) {
+ bundle.setLocation(p);
+ bundle.setSourcePathLocation( source );
+ bundle.setSourceRootPath( new Path( "src" ) );
+ bundles.add( bundle );
+ }
+ } catch (IOException e) {
+ BldCore.error( "Failed to read jar file " + f, e );
+ } catch (ModelElementFactoryException e) {
+ BldCore.error( "Failed to build bundle " + f , e );
+ } catch (RuntimeException e) {
+ BldCore.error( "Failed to build bundle " + f , e );
+ }
+ finally {
+ if ( jar != null ) {
+ try {
+ jar.close();
+ } catch (IOException e) {
+ BldCore.error( "Failed to close jar file", e );
+ }
+ }
+ }
+ }
+
+ private ISigilBundle buildBundle(Manifest manifest, File f) {
+ IBundleModelElement info = buildBundleModelElement( manifest );
+
+ ISigilBundle bundle = null;
+
+ if ( info != null ) {
+ bundle = ModelElementFactory.getInstance().newModelElement( ISigilBundle.class );
+ bundle.addChild(info);
+ bundle.setLocation( new Path( f.getAbsolutePath() ) );
+ }
+
+ return bundle;
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/repository/eclipse/OSGiInstallRepositoryProvider.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/repository/eclipse/OSGiInstallRepositoryProvider.java
new file mode 100644
index 0000000..043eb81
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/repository/eclipse/OSGiInstallRepositoryProvider.java
@@ -0,0 +1,31 @@
+/*
+ * 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.cauldron.sigil.internal.repository.eclipse;
+
+import java.util.Properties;
+
+import org.cauldron.sigil.repository.IBundleRepository;
+import org.cauldron.sigil.repository.IRepositoryProvider;
+
+public class OSGiInstallRepositoryProvider implements IRepositoryProvider {
+ public IBundleRepository createRepository(String id, Properties preferences) {
+ return new OSGiInstallRepository(id);
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/repository/eclipse/SigilRepositoryManager.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/repository/eclipse/SigilRepositoryManager.java
new file mode 100644
index 0000000..0b4b757
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/repository/eclipse/SigilRepositoryManager.java
@@ -0,0 +1,192 @@
+/*
+ * 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.cauldron.sigil.internal.repository.eclipse;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Properties;
+
+import org.cauldron.sigil.SigilCore;
+import org.cauldron.sigil.model.repository.IRepositoryModel;
+import org.cauldron.sigil.model.repository.IRepositorySet;
+import org.cauldron.sigil.model.repository.IRepositoryType;
+import org.cauldron.sigil.repository.AbstractRepositoryManager;
+import org.cauldron.sigil.repository.IBundleRepository;
+import org.cauldron.sigil.repository.IRepositoryManager;
+import org.cauldron.sigil.repository.IRepositoryProvider;
+import org.cauldron.sigil.repository.RepositoryException;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+
+public class SigilRepositoryManager extends AbstractRepositoryManager implements IRepositoryManager, IPropertyChangeListener {
+
+ private final String repositorySet;
+
+ private HashMap<String, RepositoryCache> cachedRepositories = new HashMap<String, RepositoryCache>();
+
+ class RepositoryCache {
+ private final Properties pref;
+ private final IBundleRepository repo;
+
+ RepositoryCache(Properties pref, IBundleRepository repo) {
+ this.pref = pref;
+ this.repo = repo;
+ }
+ }
+
+ public SigilRepositoryManager(String repositorySet) {
+ this.repositorySet = repositorySet;
+ }
+
+ @Override
+ public void initialise() {
+ super.initialise();
+ SigilCore.getDefault().getPreferenceStore().addPropertyChangeListener(this);
+ }
+
+ public void destroy() {
+ IPreferenceStore prefs = SigilCore.getDefault().getPreferenceStore();
+ if ( prefs != null ) {
+ prefs.removePropertyChangeListener(this);
+ }
+ }
+
+ @Override
+ protected void loadRepositories() {
+ IPreferenceStore prefs = SigilCore.getDefault().getPreferenceStore();
+
+ ArrayList<IBundleRepository> repos = new ArrayList<IBundleRepository>();
+ HashSet<String> ids = new HashSet<String>();
+
+ for ( IRepositoryModel repo : findRepositories() ) {
+ try {
+ IRepositoryProvider provider = findProvider( repo.getType() );
+ String id = repo.getId();
+ IBundleRepository repoImpl = null;
+ if ( repo.getType().isDynamic() ) {
+ String instance = "repository." + repo.getType().getId() + "." + id;
+ String loc = prefs.getString( instance + ".loc" );
+ Properties pref = loadPreferences(loc);
+ repoImpl = loadRepository(id, pref, provider);
+ }
+ else {
+ repoImpl = loadRepository(id, null, provider);
+ }
+
+ repos.add( repoImpl );
+ ids.add( id );
+ } catch (Exception e) {
+ SigilCore.error( "Failed to load repository for " + repo, e);
+ }
+ }
+
+ setRepositories(repos.toArray( new IBundleRepository[repos.size()] ) );
+
+ for ( Iterator<String> i = cachedRepositories.keySet().iterator(); i.hasNext(); ) {
+ if ( !ids.contains(i.next()) ) {
+ i.remove();
+ }
+ }
+ }
+
+ private IRepositoryProvider findProvider(IRepositoryType repositoryType) throws CoreException {
+ String id = repositoryType.getId();
+
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint p = registry.getExtensionPoint(SigilCore.REPOSITORY_PROVIDER_EXTENSION_POINT_ID);
+
+ for ( IExtension e : p.getExtensions() ) {
+ for ( IConfigurationElement c : e.getConfigurationElements() ) {
+ if ( id.equals( c.getAttribute("id") ) ) {
+ IRepositoryProvider provider = (IRepositoryProvider) c.createExecutableExtension("class");
+ return provider;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ protected IRepositoryModel[] findRepositories() {
+ if ( repositorySet == null ) {
+ return SigilCore.getRepositoryConfiguration().getDefaultRepositorySet().getRepositories();
+ }
+ else {
+ IRepositorySet set = SigilCore.getRepositoryConfiguration().getRepositorySet(repositorySet);
+ return set.getRepositories();
+ }
+ }
+
+ private IBundleRepository loadRepository(String id, Properties pref, IRepositoryProvider provider) throws RepositoryException {
+ try {
+ if ( pref == null ) {
+ pref = new Properties();
+ }
+
+ RepositoryCache cache = cachedRepositories.get(id);
+
+ if ( cache == null || !cache.pref.equals(pref) ) {
+ IBundleRepository repo = provider.createRepository(id, pref);
+ cache = new RepositoryCache(pref, repo);
+ cachedRepositories.put( id, cache );
+ }
+
+ return cache.repo;
+ } catch (RuntimeException e) {
+ throw new RepositoryException( "Failed to build repositories", e);
+ }
+ }
+
+ private Properties loadPreferences(String loc) throws FileNotFoundException, IOException {
+ FileInputStream in = null;
+ try {
+ Properties pref = new Properties();
+ pref.load(new FileInputStream(loc));
+ return pref;
+ }
+ finally {
+ if ( in != null ) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ SigilCore.error( "Failed to close file", e );
+ }
+ }
+ }
+ }
+
+ public void propertyChange(PropertyChangeEvent event) {
+ if ( event.getProperty().equals( "repository.timestamp" ) ) {
+ loadRepositories();
+ }
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/repository/eclipse/WorkspaceRepository.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/repository/eclipse/WorkspaceRepository.java
new file mode 100644
index 0000000..d144e6f
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/repository/eclipse/WorkspaceRepository.java
@@ -0,0 +1,126 @@
+/*
+ * 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.cauldron.sigil.internal.repository.eclipse;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.cauldron.sigil.SigilCore;
+import org.cauldron.sigil.model.eclipse.ISigilBundle;
+import org.cauldron.sigil.model.project.ISigilProjectModel;
+import org.cauldron.sigil.repository.AbstractBundleRepository;
+import org.cauldron.sigil.repository.IRepositoryVisitor;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceChangeEvent;
+import org.eclipse.core.resources.IResourceChangeListener;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.runtime.CoreException;
+
+public class WorkspaceRepository extends AbstractBundleRepository implements IResourceChangeListener {
+
+ private static final int UPDATE_MASK = IResourceDelta.CONTENT | IResourceDelta.DESCRIPTION | IResourceDelta.OPEN;
+ private ISigilBundle[] bundles;
+
+ public WorkspaceRepository(String id) {
+ super(id);
+ }
+
+ @Override
+ public void accept(IRepositoryVisitor visitor, int options) {
+ synchronized( this ) {
+ if ( bundles == null ) {
+ List<ISigilProjectModel> models = SigilCore.getRoot().getProjects();
+ ArrayList<ISigilBundle> tmp = new ArrayList<ISigilBundle>(models.size());
+ for ( ISigilProjectModel n : models ) {
+ ISigilBundle b = n.getBundle();
+ tmp.add(b);
+ }
+ bundles = tmp.toArray( new ISigilBundle[tmp.size()] );
+ }
+ }
+
+ for ( ISigilBundle b : bundles ) {
+ visitor.visit(b);
+ }
+ }
+
+ public void refresh() {
+ synchronized(this) {
+ bundles = null;
+ }
+ }
+
+ @Override
+ protected void notifyChange() {
+ refresh();
+ super.notifyChange();
+ }
+
+ public void resourceChanged(IResourceChangeEvent event) {
+ try {
+ event.getDelta().accept( new IResourceDeltaVisitor() {
+ public boolean visit(IResourceDelta delta) throws CoreException {
+ boolean result;
+
+ IResource resource = delta.getResource();
+ if(resource instanceof IWorkspaceRoot) {
+ result = true;
+ } else if(resource instanceof IProject) {
+ IProject project = (IProject) resource;
+ if ( SigilCore.isSigilProject(project) ) {
+ switch (delta.getKind()) {
+ case IResourceDelta.CHANGED:
+ if ( (delta.getFlags() & UPDATE_MASK) == 0 ) {
+ break;
+ }
+ // else
+ // fall through on purpose
+ case IResourceDelta.ADDED: // fall through on purpose
+ case IResourceDelta.REMOVED: // fall through on purpose
+ notifyChange();
+ break;
+ }
+ result = true;
+ } else {
+ result = false;
+ }
+ } else if(resource.getName().equals(SigilCore.SIGIL_PROJECT_FILE)) {
+ switch(delta.getKind()) {
+ case IResourceDelta.CHANGED:
+ case IResourceDelta.ADDED:
+ case IResourceDelta.REMOVED:
+ notifyChange();
+ }
+ result = false;
+ } else {
+ result = false;
+ }
+ return result;
+ }
+ });
+ } catch (CoreException e) {
+ SigilCore.error( "Workspace repository update failed", e );
+ }
+ }
+
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/repository/eclipse/WorkspaceRepositoryProvider.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/repository/eclipse/WorkspaceRepositoryProvider.java
new file mode 100644
index 0000000..b67aa25
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/internal/repository/eclipse/WorkspaceRepositoryProvider.java
@@ -0,0 +1,43 @@
+/*
+ * 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.cauldron.sigil.internal.repository.eclipse;
+
+import java.util.Properties;
+
+import org.cauldron.sigil.repository.IBundleRepository;
+import org.cauldron.sigil.repository.IRepositoryProvider;
+import org.eclipse.core.resources.IResourceChangeEvent;
+import org.eclipse.core.resources.ResourcesPlugin;
+
+public class WorkspaceRepositoryProvider implements IRepositoryProvider {
+ private static WorkspaceRepository repository;
+
+ public static WorkspaceRepository getWorkspaceRepository() {
+ return repository;
+ }
+
+ public IBundleRepository createRepository(String id, Properties preferences) {
+ if ( repository == null ) {
+ repository = new WorkspaceRepository(id);
+ ResourcesPlugin.getWorkspace().addResourceChangeListener(repository, IResourceChangeEvent.POST_CHANGE);
+ }
+ return repository;
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/job/ResolveProjectsJob.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/job/ResolveProjectsJob.java
new file mode 100644
index 0000000..243dccf
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/job/ResolveProjectsJob.java
@@ -0,0 +1,145 @@
+/*
+ * 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.cauldron.sigil.job;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+import org.cauldron.sigil.SigilCore;
+import org.cauldron.sigil.model.osgi.IPackageImport;
+import org.cauldron.sigil.model.osgi.IRequiredBundle;
+import org.cauldron.sigil.model.project.ISigilProjectModel;
+import org.cauldron.sigil.repository.IBundleResolver;
+import org.cauldron.sigil.repository.IRepositoryManager;
+import org.cauldron.sigil.repository.IResolution;
+import org.cauldron.sigil.repository.ResolutionConfig;
+import org.cauldron.sigil.repository.ResolutionException;
+import org.cauldron.sigil.repository.ResolutionMonitorAdapter;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+
+public class ResolveProjectsJob extends Job {
+
+ private final IWorkspace workspace;
+ private final IProject project;
+
+ public ResolveProjectsJob(IWorkspace workspace) {
+ super("Resolving Sigil projects");
+ this.workspace = workspace;
+ this.project = null;
+ setRule(ResourcesPlugin.getWorkspace().getRoot());
+ }
+
+ public ResolveProjectsJob(IProject project) {
+ super("Resolving Sigil project");
+ this.workspace = null;
+ this.project = project;
+ setRule(project.getFile(SigilCore.SIGIL_PROJECT_FILE));
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ MultiStatus status = new MultiStatus(SigilCore.PLUGIN_ID, 0, "Error resolving Sigil projects", null);
+
+ Collection<ISigilProjectModel> sigilProjects = null;
+
+ if(workspace != null) {
+ sigilProjects = SigilCore.getRoot().getProjects();
+ } else if(project != null) {
+ try {
+ ISigilProjectModel sigilProject = SigilCore.create(project);
+ sigilProjects = Collections.singleton(sigilProject);
+ } catch (CoreException e) {
+ status.add(e.getStatus());
+ }
+ }
+
+ if ( sigilProjects != null ) {
+ for (ISigilProjectModel sigilProject : sigilProjects) {
+ try {
+ // Delete existing dependency markers on project
+ sigilProject.getProject().deleteMarkers(SigilCore.MARKER_UNRESOLVED_DEPENDENCY, true, IResource.DEPTH_ONE);
+
+ IRepositoryManager repository = SigilCore.getRepositoryManager(sigilProject);
+ ResolutionMonitorAdapter resolutionMonitor = new ResolutionMonitorAdapter(monitor);
+
+ IBundleResolver resolver = repository.getBundleResolver();
+ ResolutionConfig config = new ResolutionConfig(ResolutionConfig.IGNORE_ERRORS);
+
+ // Execute resolver
+ IResolution resolution = resolver.resolve(sigilProject, config, resolutionMonitor);
+
+ // Find missing imports
+ Set<IPackageImport> imports = sigilProject.getBundle().getBundleInfo().getImports();
+ for (IPackageImport pkgImport : imports) {
+ if(resolution.getProvider(pkgImport) == null) {
+ markMissingImport(pkgImport, sigilProject.getProject());
+ }
+ }
+
+ // Find missing required bundles
+ Set<IRequiredBundle> requiredBundles = sigilProject.getBundle().getBundleInfo().getRequiredBundles();
+ for (IRequiredBundle requiredBundle : requiredBundles) {
+ if(resolution.getProvider(requiredBundle) == null) {
+ markMissingRequiredBundle(requiredBundle, sigilProject.getProject());
+ }
+ }
+ } catch (ResolutionException e) {
+ status.add(new Status(IStatus.ERROR, SigilCore.PLUGIN_ID, 0, "Error resolving project " + sigilProject.getProject().getName(), e));
+ } catch (CoreException e) {
+ status.add(e.getStatus());
+ }
+ }
+ }
+
+ return status;
+ }
+
+ private static void markMissingImport(IPackageImport pkgImport, IProject project) throws CoreException {
+ IMarker marker = project.getProject().createMarker(SigilCore.MARKER_UNRESOLVED_IMPORT_PACKAGE);
+ marker.setAttribute("element", pkgImport.getPackageName());
+ marker.setAttribute("versionRange", pkgImport.getVersions().toString());
+ marker.setAttribute(IMarker.MESSAGE, "Cannot resolve imported package \"" + pkgImport.getPackageName() + "\" with version range " + pkgImport.getVersions());
+ marker.setAttribute(IMarker.SEVERITY, pkgImport.isOptional() ? IMarker.SEVERITY_WARNING : IMarker.SEVERITY_ERROR);
+ marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH);
+ }
+
+ private static void markMissingRequiredBundle(IRequiredBundle req, IProject project) throws CoreException {
+ IMarker marker = project.getProject().createMarker(SigilCore.MARKER_UNRESOLVED_REQUIRE_BUNDLE);
+ marker.setAttribute("element", req.getSymbolicName());
+ marker.setAttribute("versionRange", req.getVersions().toString());
+ marker.setAttribute(IMarker.MESSAGE, "Cannot resolve required bundle \"" + req.getSymbolicName() + "\" with version range " + req.getVersions());
+ marker.setAttribute(IMarker.SEVERITY, req.isOptional() ? IMarker.SEVERITY_WARNING : IMarker.SEVERITY_ERROR);
+ marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH);
+ }
+
+
+
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/job/ThreadProgressMonitor.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/job/ThreadProgressMonitor.java
new file mode 100644
index 0000000..5c526d0
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/job/ThreadProgressMonitor.java
@@ -0,0 +1,34 @@
+/*
+ * 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.cauldron.sigil.job;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+public class ThreadProgressMonitor {
+ private static ThreadLocal<IProgressMonitor> local = new ThreadLocal<IProgressMonitor>();
+
+ public static void setProgressMonitor(IProgressMonitor monitor) {
+ local.set(monitor);
+ }
+
+ public static IProgressMonitor getProgressMonitor() {
+ return local.get();
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/project/ISigilModelRoot.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/project/ISigilModelRoot.java
new file mode 100644
index 0000000..2c9b53a
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/project/ISigilModelRoot.java
@@ -0,0 +1,36 @@
+/*
+ * 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.cauldron.sigil.model.project;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.cauldron.sigil.model.IModelElement;
+import org.cauldron.sigil.model.eclipse.ISigilBundle;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+public interface ISigilModelRoot {
+ List<ISigilProjectModel> getProjects();
+
+ Collection<ISigilProjectModel> resolveDependentProjects(ISigilProjectModel sigil, IProgressMonitor monitor);
+
+ Collection<ISigilBundle> resolveBundles(ISigilProjectModel sigil, IModelElement element, boolean includeOptional, IProgressMonitor monitor) throws CoreException;
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/project/ISigilProjectModel.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/project/ISigilProjectModel.java
new file mode 100644
index 0000000..ebb8fe9
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/project/ISigilProjectModel.java
@@ -0,0 +1,105 @@
+/*
+ * 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.cauldron.sigil.model.project;
+
+import java.util.Collection;
+
+import org.cauldron.bld.config.IBldProject;
+import org.cauldron.bld.core.BldCore;
+import org.cauldron.sigil.model.ICompoundModelElement;
+import org.cauldron.sigil.model.IModelElement;
+import org.cauldron.sigil.model.eclipse.ISigilBundle;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.JavaModelException;
+import org.osgi.framework.Version;
+import org.osgi.service.prefs.Preferences;
+
+/**
+ * Represents a sigil project. To get a reference to a ISigilProjectModel you can use the
+ * helper method {@link BldCore#create(IProject)}.
+ *
+ * @author dave
+ *
+ */
+public interface ISigilProjectModel extends ICompoundModelElement {
+
+ /**
+ * @return
+ */
+ IProject getProject();
+
+ // shortcut to getProject().getName()
+ String getName();
+
+ Preferences getPreferences();
+
+ /**
+ *
+ * @param monitor
+ * The progress monitor to use for reporting progress to the
+ * user. It is the caller's responsibility to call done() on the
+ * given monitor. Accepts null, indicating that no progress
+ * should be reported and that the operation cannot be cancelled
+ * @throws CoreException
+ */
+ void save(IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * @return
+ */
+ Version getVersion();
+
+ String getSymbolicName();
+
+ ISigilBundle getBundle();
+
+ void setBundle(ISigilBundle bundle);
+
+ /**
+ * @return
+ */
+ IJavaProject getJavaModel();
+
+ Collection<ISigilProjectModel> findDependentProjects(IProgressMonitor monitor);
+
+ void resetClasspath(IProgressMonitor monitor) throws CoreException;
+
+ IPath findBundleLocation() throws CoreException;
+
+ IModelElement findImport(String packageName, IProgressMonitor monitor);
+
+ boolean isInClasspath(String packageName, IProgressMonitor monitor) throws CoreException;
+
+ boolean isInClasspath(ISigilBundle bundle);
+
+ boolean isInBundleClasspath(IPackageFragmentRoot root) throws JavaModelException;
+
+ IPath findOutputLocation() throws CoreException;
+
+ IBldProject getBldProject() throws CoreException;
+
+ Collection<IClasspathEntry> findExternalClasspath(IProgressMonitor monitor) throws CoreException;
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/repository/IRepositoryConfiguration.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/repository/IRepositoryConfiguration.java
new file mode 100644
index 0000000..7c62e6c
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/repository/IRepositoryConfiguration.java
@@ -0,0 +1,49 @@
+/*
+ * 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.cauldron.sigil.model.repository;
+
+import java.util.List;
+import java.util.Map;
+
+import org.cauldron.sigil.internal.model.repository.RepositoryType;
+import org.eclipse.core.runtime.CoreException;
+
+public interface IRepositoryConfiguration {
+
+ List<IRepositoryModel> loadRepositories();
+
+ IRepositoryModel findRepository(String id);
+
+ void saveRepositories(List<IRepositoryModel> repositories) throws CoreException;
+
+ List<RepositoryType> loadRepositoryTypes();
+
+ IRepositoryModel newRepositoryElement(IRepositoryType type);
+
+ IRepositorySet getDefaultRepositorySet();
+
+ void setDefaultRepositorySet(IRepositorySet defaultSet);
+
+ IRepositorySet getRepositorySet(String name);
+
+ Map<String, IRepositorySet> loadRepositorySets();
+
+ void saveRepositorySets(Map<String, IRepositorySet> sets);
+}
\ No newline at end of file
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/repository/IRepositoryModel.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/repository/IRepositoryModel.java
new file mode 100644
index 0000000..182998f
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/repository/IRepositoryModel.java
@@ -0,0 +1,35 @@
+/*
+ * 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.cauldron.sigil.model.repository;
+
+import org.eclipse.jface.preference.PreferenceStore;
+
+public interface IRepositoryModel {
+
+ String getId();
+
+ void setName(String stringValue);
+
+ String getName();
+
+ PreferenceStore getPreferences();
+
+ IRepositoryType getType();
+}
\ No newline at end of file
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/repository/IRepositorySet.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/repository/IRepositorySet.java
new file mode 100644
index 0000000..b4e644b
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/repository/IRepositorySet.java
@@ -0,0 +1,27 @@
+/*
+ * 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.cauldron.sigil.model.repository;
+
+public interface IRepositorySet {
+ void setRepository(IRepositoryModel id, int position);
+ void removeRepository(IRepositoryModel id);
+ IRepositoryModel[] getRepositories();
+ void setRepositories(IRepositoryModel[] repositories);
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/repository/IRepositoryType.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/repository/IRepositoryType.java
new file mode 100644
index 0000000..33df100
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/repository/IRepositoryType.java
@@ -0,0 +1,34 @@
+/*
+ * 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.cauldron.sigil.model.repository;
+
+import org.eclipse.swt.graphics.Image;
+
+public interface IRepositoryType {
+
+ String getType();
+
+ String getId();
+
+ Image getIcon();
+
+ boolean isDynamic();
+
+}
\ No newline at end of file
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/repository/RepositorySet.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/repository/RepositorySet.java
new file mode 100644
index 0000000..5630a6d
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/repository/RepositorySet.java
@@ -0,0 +1,63 @@
+/*
+ * 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.cauldron.sigil.model.repository;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class RepositorySet implements IRepositorySet {
+
+ private static final IRepositoryModel[] EMPTY = new IRepositoryModel[0];
+
+ private IRepositoryModel[] reps;
+
+ public RepositorySet() {
+ this( EMPTY );
+ }
+
+ public RepositorySet(Collection<IRepositoryModel> reps) {
+ this( reps.toArray( new IRepositoryModel[reps.size()] ) );
+ }
+
+ public RepositorySet(IRepositoryModel[] repositories) {
+ this.reps = repositories;
+ }
+
+ public void setRepository(IRepositoryModel id, int position) {
+ ArrayList<IRepositoryModel> tmp = new ArrayList<IRepositoryModel>(reps.length + 1);
+ tmp.remove(id);
+ tmp.add(position, id);
+ reps = tmp.toArray( new IRepositoryModel[tmp.size()] );
+ }
+
+ public IRepositoryModel[] getRepositories() {
+ return reps;
+ }
+
+ public void removeRepository(IRepositoryModel id) {
+ ArrayList<IRepositoryModel> tmp = new ArrayList<IRepositoryModel>(reps.length + 1);
+ tmp.remove(id);
+ reps = tmp.toArray( new IRepositoryModel[tmp.size()] );
+ }
+
+ public void setRepositories(IRepositoryModel[] repositories) {
+ reps = repositories == null ? EMPTY : repositories;
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/util/Grep.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/util/Grep.java
new file mode 100644
index 0000000..b2c7854
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/util/Grep.java
@@ -0,0 +1,108 @@
+/*
+ * 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.cauldron.sigil.model.util;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.CharBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+
+public class Grep {
+
+ // Pattern used to parse lines
+ private static Pattern linePattern = Pattern.compile(".*\r?\n");
+
+ // The input pattern that we're looking for
+ private Pattern pattern;
+
+ private CharBuffer cb;
+
+ private FileChannel fc;
+
+ private Grep(IFile f, Pattern pattern) throws IOException, CoreException {
+ this.pattern = pattern;
+ cb = openBuffer(f);
+ }
+
+ private CharBuffer openBuffer(IFile f) throws IOException, CoreException {
+ Charset charset = Charset.forName(f.getCharset());
+ CharsetDecoder decoder = charset.newDecoder();
+ // Open the file and then get a channel from the stream
+ FileInputStream fis = new FileInputStream(f.getLocation().toFile());
+ fc = fis.getChannel();
+
+ // Get the file's size and then map it into memory
+ int sz = (int) fc.size();
+ MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, sz);
+
+ // Decode the file into a char buffer
+ return decoder.decode(bb);
+ }
+
+ public static String[] grep(Pattern pattern, IFile...files) throws CoreException {
+ LinkedList<String> matches = new LinkedList<String>();
+ for ( IFile f : files ) {
+ try {
+ Grep g = new Grep( f, pattern );
+ g.grep(matches);
+ g.close();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ return matches.toArray( new String[matches.size()]);
+ }
+
+ private void close() throws IOException {
+ fc.close();
+ }
+
+ // Use the linePattern to break the given CharBuffer into lines, applying
+ // the input pattern to each line to see if we have a match
+ //
+ private void grep(List<String> matches) {
+ Matcher lm = linePattern.matcher(cb); // Line matcher
+ Matcher pm = null; // Pattern matcher
+ int lines = 0;
+ while (lm.find()) {
+ lines++;
+ CharSequence cs = lm.group(); // The current line
+ if (pm == null)
+ pm = pattern.matcher(cs);
+ else
+ pm.reset(cs);
+ if (pm.find())
+ matches.add(pm.group());
+ if (lm.end() == cb.limit())
+ break;
+ }
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/util/JavaHelper.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/util/JavaHelper.java
new file mode 100644
index 0000000..1c87c87
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/util/JavaHelper.java
@@ -0,0 +1,985 @@
+/*
+ * 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.cauldron.sigil.model.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+import java.util.regex.Pattern;
+
+import org.cauldron.sigil.SigilCore;
+import org.cauldron.sigil.model.IModelElement;
+import org.cauldron.sigil.model.IModelWalker;
+import org.cauldron.sigil.model.ModelElementFactory;
+import org.cauldron.sigil.model.common.VersionRange;
+import org.cauldron.sigil.model.common.VersionRangeBoundingRule;
+import org.cauldron.sigil.model.eclipse.ISCAComposite;
+import org.cauldron.sigil.model.eclipse.ISigilBundle;
+import org.cauldron.sigil.model.osgi.IPackageExport;
+import org.cauldron.sigil.model.osgi.IPackageImport;
+import org.cauldron.sigil.model.osgi.IRequiredBundle;
+import org.cauldron.sigil.model.project.ISigilProjectModel;
+import org.cauldron.sigil.repository.IRepositoryManager;
+import org.cauldron.sigil.repository.IResolution;
+import org.cauldron.sigil.repository.ResolutionConfig;
+import org.cauldron.sigil.repository.ResolutionException;
+import org.cauldron.sigil.repository.ResolutionMonitorAdapter;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.content.IContentDescription;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.core.runtime.content.IContentTypeManager;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jdt.core.IAccessRule;
+import org.eclipse.jdt.core.IAnnotation;
+import org.eclipse.jdt.core.IClassFile;
+import org.eclipse.jdt.core.IClasspathAttribute;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IField;
+import org.eclipse.jdt.core.IImportDeclaration;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.ILocalVariable;
+import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.IParent;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.ITypeHierarchy;
+import org.eclipse.jdt.core.ITypeRoot;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.Signature;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.osgi.framework.Version;
+
+/**
+ * @author dave
+ *
+ */
+public class JavaHelper {
+
+ public static final IAccessRule DENY_RULE = JavaCore.newAccessRule(
+ new Path("**"), IAccessRule.K_NON_ACCESSIBLE
+ | IAccessRule.IGNORE_IF_BETTER);
+
+ public static final IAccessRule ALLOW_ALL_RULE = JavaCore.newAccessRule(
+ new Path("**"), IAccessRule.K_ACCESSIBLE);
+
+ private static Map<String, Collection<IClasspathEntry>> entryCache = new HashMap<String, Collection<IClasspathEntry>>();
+
+ public static Collection<IClasspathEntry> findClasspathEntries(ISigilBundle bundle) {
+ LinkedList<IClasspathEntry> cp = new LinkedList<IClasspathEntry>();
+
+ ISigilProjectModel sp = bundle.getAncestor(ISigilProjectModel.class);
+
+ if ( sp != null ) {
+ IJavaProject p = sp.getJavaModel();
+
+ for ( String enc : bundle.getClasspathEntrys() ) {
+ IClasspathEntry e = p.decodeClasspathEntry(enc);
+ if ( e != null ) {
+ cp.add( e );
+ }
+ }
+ }
+
+ return cp;
+ }
+
+ public static Collection<ICompilationUnit> findCompilationUnits(ISigilProjectModel project) throws JavaModelException {
+ LinkedList<ICompilationUnit> ret = new LinkedList<ICompilationUnit>();
+
+ IJavaProject java = project.getJavaModel();
+ for ( IClasspathEntry cp : findClasspathEntries(project.getBundle()) ) {
+ IPackageFragmentRoot[] roots = java.findPackageFragmentRoots(cp);
+ for (IPackageFragmentRoot rt : roots ) {
+ for ( IJavaElement j : rt.getChildren() ) {
+ IPackageFragment p = (IPackageFragment) j;
+ ICompilationUnit[] units = p.getCompilationUnits();
+ for ( ICompilationUnit u : units ) {
+ ret.add( u );
+ }
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ /**
+ * @param project
+ * @param packageName
+ * @return
+ */
+ public static Collection<IPackageExport> findExportsForPackage(ISigilProjectModel project, final String packageName) {
+ final LinkedList<IPackageExport> results = new LinkedList<IPackageExport>();
+
+ SigilCore.getRepositoryManager(project).visit(new IModelWalker() {
+ public boolean visit(IModelElement element) {
+ if ( element instanceof IPackageExport ) {
+ IPackageExport e = (IPackageExport) element;
+ if ( e.getPackageName().equals( packageName ) ) {
+ results.add( e );
+ }
+ }
+ return true;
+ }
+ });
+
+ return results;
+ }
+
+ public static String[] findUses(String packageName, ISigilProjectModel projectModel) throws CoreException {
+ ArrayList<String> uses = new ArrayList<String>();
+
+ for ( final String dependency : findPackageDependencies( packageName, projectModel ) ) {
+ if ( !dependency.equals( packageName ) ) {
+ final boolean[] found = new boolean[1];
+
+ projectModel.visit( new IModelWalker() {
+
+ public boolean visit(IModelElement element) {
+ if ( element instanceof IPackageImport ) {
+ IPackageImport pi = (IPackageImport) element;
+ if ( pi.getPackageName().equals( dependency ) ) {
+ found[0] = true;
+ }
+ }
+ return !found[0];
+ }
+ } );
+
+ if ( found[0] ) {
+ uses.add( dependency );
+ }
+ }
+ }
+
+ return uses.toArray( new String[uses.size()] );
+ }
+
+ private static String[] findPackageDependencies(String packageName, ISigilProjectModel projectModel) throws CoreException {
+ HashSet<String> imports = new HashSet<String>();
+
+ IPackageFragment p = (IPackageFragment) projectModel.getJavaModel().findElement( new Path(packageName.replace('.', '/') ) );
+
+ if ( p == null ) {
+ throw SigilCore.newCoreException("Unknown package " + packageName, null);
+ }
+ for (ICompilationUnit cu : p.getCompilationUnits() ) {
+ scanImports(cu, imports);
+ }
+ for (IClassFile cf : p.getClassFiles() ) {
+ scanImports(cf, imports);
+ }
+
+ return imports.toArray( new String[imports.size()] );
+ }
+
+ /**
+ * @param project
+ * @param monitor
+ * @return
+ */
+ public static List<IPackageImport> findRequiredImports(ISigilProjectModel project, IProgressMonitor monitor) {
+ LinkedList<IPackageImport> imports = new LinkedList<IPackageImport>();
+
+ for ( String packageName : findJavaImports(project, monitor)) {
+ if ( !ProfileManager.isBootDelegate(project, packageName) ) { // these must come from boot classloader
+ try {
+ if ( !project.isInClasspath(packageName, monitor) ) {
+ Collection<IPackageExport> exports = findExportsForPackage(project, packageName);
+ if ( !exports.isEmpty() ) {
+ imports.add( select( exports ) );
+ }
+ }
+ } catch (CoreException e) {
+ SigilCore.error( "Failed to check classpath", e );
+ }
+ }
+ }
+
+ return imports;
+ }
+
+ /**
+ * @param project
+ * @param monitor
+ * @return
+ */
+ public static Collection<IModelElement> findUnusedReferences(final ISigilProjectModel project, final IProgressMonitor monitor) {
+ final LinkedList<IModelElement> unused = new LinkedList<IModelElement>();
+
+ final Set<String> packages = findJavaImports(project, monitor);
+
+ project.visit( new IModelWalker() {
+ public boolean visit(IModelElement element) {
+ if ( element instanceof IPackageImport ) {
+ IPackageImport pi = (IPackageImport) element;
+ if ( !packages.contains( pi.getPackageName() ) ) {
+ unused.add( pi );
+ }
+ }
+ else if ( element instanceof IRequiredBundle ) {
+ IRequiredBundle rb = (IRequiredBundle) element;
+ IRepositoryManager manager = SigilCore.getRepositoryManager(project);
+ ResolutionConfig config = new ResolutionConfig(ResolutionConfig.INCLUDE_OPTIONAL | ResolutionConfig.IGNORE_ERRORS);
+ try {
+ IResolution r = manager.getBundleResolver().resolve(rb, config ,
+ new ResolutionMonitorAdapter(monitor) );
+ ISigilBundle bundle = r.getProvider(rb);
+ boolean found = false;
+ for ( IPackageExport pe : bundle.getBundleInfo().getExports() ) {
+ if ( packages.contains(pe.getPackageName() ) ) {
+ found = true;
+ break;
+ }
+ }
+
+ if ( !found ) {
+ unused.add( rb );
+ }
+ } catch (ResolutionException e) {
+ SigilCore.error( "Failed to resolve " + rb, e );
+ }
+ }
+ return true;
+ }
+ });
+
+ return unused;
+ }
+
+ public static Collection<IClasspathEntry> resolveClasspathEntrys(ISigilProjectModel sigil, IProgressMonitor monitor)
+ throws CoreException {
+ if ( monitor == null ) {
+ monitor = Job.getJobManager().createProgressGroup();
+ monitor.beginTask("Resolving classpath for "
+ + sigil.getSymbolicName(), 2);
+ }
+
+ ArrayList<IClasspathEntry> entries = new ArrayList<IClasspathEntry>();
+
+ ResolutionConfig config = new ResolutionConfig(ResolutionConfig.INCLUDE_OPTIONAL | ResolutionConfig.IGNORE_ERRORS | ResolutionConfig.INDEXED_ONLY | ResolutionConfig.LOCAL_ONLY);
+
+ IResolution resolution;
+ try {
+ resolution = SigilCore.getRepositoryManager(sigil).getBundleResolver().resolve(sigil, config, new ResolutionMonitorAdapter(monitor));
+ } catch (ResolutionException e) {
+ throw SigilCore.newCoreException("Failed to resolve dependencies", e);
+ }
+
+ monitor.worked(1);
+
+ for (ISigilBundle bundle : resolution.getBundles()) {
+ if (!bundle.getBundleInfo().getSymbolicName().equals(sigil.getSymbolicName())) { // discard self reference...
+ List<IModelElement> matched = resolution.getMatchedRequirements(bundle);
+ for (IClasspathEntry cpe : buildClassPathEntry(sigil, bundle, matched, monitor)) {
+ entries.add(cpe);
+ }
+ }
+ }
+
+ monitor.worked(1);
+ monitor.done();
+
+ return entries;
+ }
+
+ private static Collection<IClasspathEntry> buildClassPathEntry(ISigilProjectModel project, ISigilBundle provider, List<IModelElement> requirements, IProgressMonitor monitor) throws CoreException {
+ IAccessRule[] rules = buildAccessRules(project, provider, requirements);
+
+ ISigilProjectModel other = provider.getAncestor(ISigilProjectModel.class);
+
+ try {
+ if (other == null) {
+ provider.synchronize(monitor);
+ return newBundleEntry(provider, rules, null, false);
+ } else {
+ return newProjectEntry(other, rules, null, false);
+ }
+ } catch (IOException e) {
+ throw SigilCore.newCoreException("Failed to synchronize " + provider, e);
+ }
+ }
+
+ private static IAccessRule[] buildExportRules(ISigilBundle bundle) {
+ Set<IPackageExport> ex = bundle.getBundleInfo().getExports();
+ IAccessRule[] rules = new IAccessRule[ex.size() + 1];
+
+ Iterator<IPackageExport> iter = ex.iterator();
+ for (int i = 0; i < rules.length - 1; i++) {
+ IPackageExport p = iter.next();
+ rules[i] = JavaCore.newAccessRule(new Path(p.getPackageName()
+ .replace('.', '/')).append("*"), IAccessRule.K_ACCESSIBLE);
+ }
+
+ rules[rules.length - 1] = DENY_RULE;
+
+ return rules;
+ }
+
+ private static Collection<IClasspathEntry> newProjectEntry(
+ ISigilProjectModel n, IAccessRule[] rules,
+ IClasspathAttribute[] attributes, boolean export)
+ throws CoreException {
+ if (rules == null) {
+ rules = JavaHelper.buildExportRules(n.getBundle());
+ }
+
+ if (attributes == null) {
+ attributes = new IClasspathAttribute[] {};
+ }
+
+ ArrayList<IClasspathEntry> entries = new ArrayList<IClasspathEntry>();
+ entries.add(JavaCore.newProjectEntry(n.getProject().getFullPath(),
+ rules, false, attributes, export));
+ for (IClasspathEntry e : n.getJavaModel().getRawClasspath()) {
+ switch (e.getEntryKind()) {
+ case IClasspathEntry.CPE_LIBRARY:
+ entries.add(JavaCore.newLibraryEntry(e.getPath(), e
+ .getSourceAttachmentPath(), e
+ .getSourceAttachmentRootPath(), rules, attributes,
+ export));
+ break;
+ case IClasspathEntry.CPE_VARIABLE:
+ IPath path = JavaCore.getResolvedVariablePath(e.getPath());
+ if (path != null) {
+ entries.add(JavaCore.newLibraryEntry(path, e
+ .getSourceAttachmentPath(), e
+ .getSourceAttachmentRootPath(), rules, attributes,
+ export));
+ }
+ break;
+ }
+ }
+
+ return entries;
+ }
+
+ private static Collection<IClasspathEntry> newBundleEntry(
+ ISigilBundle bundle, IAccessRule[] rules,
+ IClasspathAttribute[] attributes, boolean exported)
+ throws CoreException {
+ String name = bundle.getBundleInfo().getSymbolicName();
+
+ if (rules == null) {
+ rules = JavaHelper.buildExportRules(bundle);
+ }
+
+ if (attributes == null) {
+ attributes = new IClasspathAttribute[] {};
+ }
+
+ if (bundle.getBundleInfo().getVersion() != null) {
+ name += "_version_" + bundle.getBundleInfo().getVersion();
+ }
+
+ String cacheName = name + rules.toString();
+
+ Collection<IClasspathEntry> entries = null;
+
+ synchronized( entryCache ) {
+ entries = entryCache.get(cacheName);
+
+ if (entries == null) {
+ IPath path = bundle.getLocation();
+
+ if (path == null) {
+ SigilCore.error("Found null path for "
+ + bundle.getBundleInfo().getSymbolicName());
+ entries = Collections.emptyList();
+ } else {
+ entries = buildEntries(path, name, bundle, rules, attributes,
+ exported);
+ }
+
+ entryCache.put(cacheName, entries);
+ }
+ }
+
+ return entries;
+ }
+
+ private static IPath bundleCache = SigilCore.getDefault().getStateLocation().append(
+ "bundle-cache");
+
+ public static boolean isCachedBundle(String bp) {
+ return bp.startsWith(bundleCache.toOSString());
+ }
+
+ private static Collection<IClasspathEntry> buildEntries(IPath path,
+ String name, ISigilBundle bundle, IAccessRule[] rules,
+ IClasspathAttribute[] attributes, boolean exported)
+ throws CoreException {
+ if (path.toFile().isDirectory()) {
+ throw SigilCore.newCoreException("Bundle location cannot be a directory",
+ null);
+ } else {
+ // ok it's a jar could contain libs etc
+ try {
+ IPath cache = bundleCache.append(name);
+ Set<String> files = unpack(cache, bundle);
+ Set<String> classpath = filterClasspath(bundle.getBundleInfo().getClasspaths(), files);
+ ArrayList<IClasspathEntry> entries = new ArrayList<IClasspathEntry>(
+ classpath.size());
+
+ for (String cp : classpath) {
+ IPath p = ".".equals(cp) ? path : cache.append(cp);
+ IPath source = bundle.getSourcePathLocation();
+
+ if (source != null && !source.toFile().exists()) {
+ source = null;
+ }
+
+ IClasspathEntry e = JavaCore.newLibraryEntry(p, source,
+ bundle.getSourceRootPath(), rules, attributes,
+ exported);
+ entries.add(e);
+ }
+
+ return entries;
+ } catch (IOException e) {
+ throw SigilCore.newCoreException("Failed to unpack bundle", e);
+ }
+ }
+ }
+
+ private static Set<String> filterClasspath(Collection<String> classpaths,
+ Collection<String> files) {
+ HashSet<String> cp = new HashSet<String>(classpaths);
+ for (String c : cp) {
+ if (".".equals(c)) {
+ // ignore
+ } else {
+ if (!files.remove(c)) {
+ break;
+ }
+ }
+ }
+
+ if (files.isEmpty()) {
+ cp.remove(".");
+ }
+
+ return cp;
+ }
+
+ private static HashMap<IPath, Set<String>> unpacked = new HashMap<IPath, Set<String>>();
+
+ private static synchronized Set<String> unpack(IPath cache,
+ ISigilBundle bundle) throws IOException {
+ Set<String> files = unpacked.get(cache);
+
+ if ( files == null ) {
+ files = new HashSet<String>();
+ File dir = createEmptyDir(cache);
+ JarInputStream in = new JarInputStream(new FileInputStream(bundle
+ .getLocation().toFile()));
+ JarEntry entry;
+ while ((entry = in.getNextJarEntry()) != null) {
+ File f = new File(dir, entry.getName());
+ if (entry.isDirectory()) {
+ createDir(f);
+ } else {
+ try {
+ File p = f.getParentFile();
+ createDir(p);
+ streamTo(in, f);
+ files.add(entry.getName());
+ }
+ catch (RuntimeException e) {
+ SigilCore.error("Failed to unpack " + entry, e);
+ }
+ }
+ }
+
+ unpacked.put(cache, files);
+ }
+ return files;
+ }
+
+ private static void createDir(File p) throws IOException {
+ if (!p.exists()) {
+ if (!p.mkdirs())
+ throw new IOException("Failed to create directory " + p);
+ }
+ }
+
+ private static void streamTo(InputStream in, File f) throws IOException {
+ FileOutputStream fos = new FileOutputStream(f);
+ try {
+ byte[] buf = new byte[1024];
+ for (;;) {
+ int r = in.read(buf);
+
+ if (r == -1)
+ break;
+
+ fos.write(buf, 0, r);
+ }
+
+ fos.flush();
+ } finally {
+ try {
+ fos.close();
+ } catch (IOException e) {
+ SigilCore.error("Failed to close stream", e);
+ }
+ }
+ }
+
+ private static File createEmptyDir(IPath cache) {
+ File dir = cache.toFile();
+ if (dir.exists()) {
+ deleteAll(dir);
+ }
+
+ dir.mkdirs();
+ return dir;
+ }
+
+ private static void deleteAll(File file) {
+ File[] sub = file.listFiles();
+ if (sub != null) {
+ for (File f : sub) {
+ deleteAll(f);
+ }
+ }
+ file.delete();
+ }
+
+ private static IAccessRule[] buildAccessRules(ISigilProjectModel project, ISigilBundle bundle, List<IModelElement> requirements) throws JavaModelException {
+ ArrayList<IAccessRule> rules = new ArrayList<IAccessRule>();
+
+ for (IModelElement e : requirements) {
+ if (e instanceof IRequiredBundle) {
+ IRequiredBundle host = project.getBundle().getBundleInfo().getFragmentHost();
+ if ( host != null ) {
+ if ( host.equals(e) ) {
+ return new IAccessRule[] { ALLOW_ALL_RULE };
+ }
+ else {
+ return buildExportRules(bundle);
+ }
+ }
+ else {
+ return buildExportRules(bundle);
+ }
+ } else if (e instanceof IPackageImport) {
+ IPackageImport pi = (IPackageImport) e;
+ String pckg = pi.getPackageName();
+ HashSet<String> pckgs = new HashSet<String>();
+ pckgs.add(pckg);
+ //findIndirectReferences(pckgs, pckg, project.getJavaModel(), project.getJavaModel());
+
+ for ( String p : pckgs ) {
+ rules.add(newPackageAccess(p));
+ }
+ }
+ }
+
+ rules.add(DENY_RULE);
+
+ return rules.toArray(new IAccessRule[rules.size()]);
+ }
+
+ /*
+ * Searches for C (and D, E, etc) in case:
+ * A extends B extends C where A, B and C are in different packages and A is in this bundle
+ * and B and C are in one or more external bundles
+ */
+ private static void findIndirectReferences(Set<String> indirect, String pckg, IParent parent, IJavaProject p) throws JavaModelException {
+ for ( IJavaElement e : parent.getChildren() ) {
+ boolean skip = false;
+ switch ( e.getElementType() ) {
+ case IJavaElement.PACKAGE_FRAGMENT_ROOT:
+ IPackageFragmentRoot rt = (IPackageFragmentRoot) e;
+ IClasspathEntry ce = rt.getRawClasspathEntry();
+ IPath path = ce.getPath();
+ skip = "org.eclipse.jdt.launching.JRE_CONTAINER".equals(path.toString());
+ break;
+ case IJavaElement.CLASS_FILE:
+ IClassFile cf = (IClassFile) e;
+ if ( cf.getElementName().startsWith(pckg) ) {
+ findIndirectReferences(indirect, findPackage(cf.getType().getSuperclassName()), p, p);
+ }
+ break;
+ case IJavaElement.COMPILATION_UNIT:
+ ICompilationUnit cu = (ICompilationUnit) e;
+ break;
+ }
+
+ if ( !skip && e instanceof IParent ) {
+ IParent newParent = (IParent) e;
+ findIndirectReferences(indirect, pckg, newParent, p);
+ }
+ }
+ }
+
+ private static IAccessRule newPackageAccess(String packageName) {
+ return JavaCore.newAccessRule(new Path(packageName.replace('.', '/'))
+ .append("*"), IAccessRule.K_ACCESSIBLE);
+ }
+
+ private static Set<String> findJavaImports(ISigilProjectModel project, IProgressMonitor monitor) {
+ Set<String> imports = new HashSet<String>();
+
+ findJavaModelImports(project, imports, monitor);
+ findSCAImports(project, imports, monitor);
+ findTextImports(project, imports, monitor);
+
+ return imports;
+ }
+
+ private static void findSCAImports(ISigilProjectModel project, Set<String> imports, IProgressMonitor monitor) {
+ for ( ISCAComposite sca : project.getBundle().getComposites() ) {
+ IFile f = project.getProject().getFile(sca.getLocation());
+ if ( f.exists() ) {
+ try {
+ // TODO for now just treats sca as text files - should build in richer model that is able to detect java elements
+ parseText( f, imports );
+ } catch (CoreException e) {
+ SigilCore.error( "Failed to parse sca file " + f, e );
+ }
+ }
+ }
+ }
+
+ private static void findTextImports(ISigilProjectModel project, Set<String> imports, IProgressMonitor monitor) {
+ IContentTypeManager contentTypeManager = Platform.getContentTypeManager();
+ IContentType txt = contentTypeManager.getContentType("org.eclipse.core.runtime.text");
+ for ( IPath p : project.getBundle().getSourcePaths() ) {
+ IFile f = project.getProject().getFile(p);
+ if ( f.exists() ) {
+ try {
+ IContentDescription desc = f.getContentDescription();
+ if ( desc != null ) {
+ IContentType type = desc.getContentType();
+ if ( type != null ) {
+ if ( type.isKindOf( txt ) ) {
+ parseText( f, imports );
+ }
+ }
+ }
+ } catch (CoreException e) {
+ SigilCore.error( "Failed to parse text file " + f, e );
+ }
+ }
+ }
+ }
+
+ private static void findJavaModelImports(ISigilProjectModel project, Set<String> imports, IProgressMonitor monitor) {
+ try {
+ for ( IPackageFragment root : project.getJavaModel().getPackageFragments() ) {
+ IPackageFragmentRoot rt = (IPackageFragmentRoot) root.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
+
+ if ( isInClassPath( project, rt ) ) {
+ for ( ICompilationUnit cu : root.getCompilationUnits() ) {
+ scanImports( cu, imports );
+ }
+
+ for ( IClassFile cf : root.getClassFiles() ) {
+ scanImports( cf, imports );
+ }
+ }
+ }
+ } catch (JavaModelException e) {
+ SigilCore.error( "Failed to parse java model", e );
+ }
+ }
+
+ // matches word.word.word.word.Word
+ private static final Pattern JAVA_CLASS_PATTERN = Pattern.compile("((\\w*\\.\\w*)+?)\\.[A-Z]\\w*");
+
+ private static void parseText(IFile f, Set<String> imports) throws CoreException {
+ for ( String result : Grep.grep( JAVA_CLASS_PATTERN, f) ) {
+ findImport(result, imports);
+ }
+ }
+
+ private static boolean isInClassPath(ISigilProjectModel project, IPackageFragmentRoot rt) throws JavaModelException {
+ String path = encode( project, rt.getRawClasspathEntry() );
+ return project.getBundle().getClasspathEntrys().contains( path );
+ }
+
+ private static String encode(ISigilProjectModel project, IClasspathEntry cp) {
+ return project.getJavaModel().encodeClasspathEntry(cp).trim();
+ }
+
+ private static void scanImports(IParent parent, Set<String> imports) throws JavaModelException {
+ for ( IJavaElement e : parent.getChildren() ) {
+ switch ( e.getElementType() ) {
+ case IJavaElement.TYPE:
+ handleType( (IType) e, imports );
+ break;
+ case IJavaElement.IMPORT_DECLARATION:
+ handleImport( (IImportDeclaration) e, imports );
+ break;
+ case IJavaElement.FIELD:
+ handleField( (IField) e, imports );
+ break;
+ case IJavaElement.LOCAL_VARIABLE:
+ handleLocalVariable( (ILocalVariable) e, imports );
+ break;
+ case IJavaElement.ANNOTATION:
+ handleAnnotation( (IAnnotation) e, imports );
+ break;
+ case IJavaElement.METHOD:
+ handleMethod( (IMethod) e, imports );
+ break;
+ default:
+ // no action
+ break;
+ }
+
+ if ( e instanceof IParent ) {
+ scanImports((IParent) e, imports);
+ }
+ }
+ }
+
+ private static void handleType(IType e, Set<String> imports) throws JavaModelException {
+ findImportFromType(e.getSuperclassTypeSignature(), imports);
+ for ( String sig : e.getSuperInterfaceTypeSignatures() ) {
+ findImportFromType(sig, imports);
+ }
+ //findImportsForSuperTypes(e, imports);
+ }
+
+ /*private static void findImportsForSuperTypes(IType e, Set<String> imports) throws JavaModelException {
+ IJavaProject project = (IJavaProject) e.getAncestor(IJavaModel.JAVA_PROJECT);
+ LinkedList<String> types = new LinkedList<String>();
+ types.add( decodeSignature(e.getSuperclassTypeSignature()) );
+ for ( String sig : e.getSuperInterfaceTypeSignatures() ) {
+ types.add( decodeSignature(sig) );
+ }
+
+ for ( IPackageFragmentRoot root : project.getPackageFragmentRoots() ) {
+ // only need to search binary files for inheritance as source will automatically be searched
+ if ( root.getKind() == IPackageFragmentRoot.K_BINARY ) {
+ for ( String t : types ) {
+ String pac = findPackage(t);
+ if ( pac != null ) {
+ IPackageFragment fragment = root.getPackageFragment(pac);
+ if ( fragment != null ) {
+ IClassFile c = fragment.getClassFile(findClass(t));
+ if ( c != null ) {
+ findImportsForSuperTypes(c.getType(), imports);
+ }
+ }
+ }
+ }
+ }
+ }
+ } */
+
+ private static void handleMethod(IMethod e, Set<String> imports) throws JavaModelException {
+ findImportFromType(e.getReturnType(), imports);
+
+ for ( String param : e.getParameterTypes() ) {
+ findImportFromType(param, imports);
+ }
+
+ for ( String ex : e.getExceptionTypes() ) {
+ findImportFromType( ex, imports );
+ }
+ }
+
+ private static void handleAnnotation(IAnnotation e, Set<String> imports) {
+ findImport(e.getElementName(), imports);
+ }
+
+ private static void handleLocalVariable(ILocalVariable e, Set<String> imports) {
+ findImportFromType(e.getTypeSignature(), imports);
+ }
+
+ private static void handleField(IField e, Set<String> imports) throws IllegalArgumentException, JavaModelException {
+ findImportFromType(Signature.getElementType(e.getTypeSignature()), imports);
+ }
+
+ private static void handleImport(IImportDeclaration id, Set<String> imports) {
+ findImport( id.getElementName(), imports);
+ }
+
+ private static void findImportFromType(String type, Set<String> imports) {
+ String element = decodeSignature(type);
+ findImport(element, imports);
+ }
+
+ private static String decodeSignature(String type) {
+ return decodeSignature(type, false);
+ }
+
+ private static String decodeSignature(String type, boolean resolve) {
+ if ( type == null ) {
+ return null;
+ }
+
+ if ( type.length() > 0 ) {
+ switch ( type.charAt(0) ) {
+ case Signature.C_ARRAY:
+ return decodeSignature(type.substring(1) );
+ case Signature.C_UNRESOLVED:
+ return resolve ? resolve( type.substring(1, type.length() - 1) ) : null;
+ case Signature.C_RESOLVED:
+ return type.substring(1);
+ }
+ }
+ return type;
+ }
+
+ private static String resolve(String substring) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ private static void findImport(String clazz, Set<String> imports) {
+ String packageName = findPackage(clazz);
+ if ( packageName != null ) {
+ imports.add(packageName);
+ }
+ }
+
+ private static String findPackage(String clazz) {
+ if ( clazz == null ) return null;
+ int pos = clazz.lastIndexOf( '.' );
+ return pos == -1 ? null : clazz.substring(0, pos);
+ }
+
+ private static String findClass(String clazz) {
+ if ( clazz == null ) return null;
+ int pos = clazz.lastIndexOf( '.' );
+ return pos == -1 ? null : clazz.substring(pos + 1);
+ }
+
+ private static IPackageImport select(Collection<IPackageExport> proposals) {
+ IPackageExport pe = null;
+
+ for ( IPackageExport check : proposals ) {
+ if ( pe == null || check.getVersion().compareTo( pe.getVersion() ) > 0 ) {
+ pe = check;
+ }
+ }
+
+ String packageName = pe.getPackageName();
+
+ IPreferenceStore store = SigilCore.getDefault().getPreferenceStore();
+ VersionRangeBoundingRule lowerBoundRule = VersionRangeBoundingRule.valueOf(store.getString(SigilCore.DEFAULT_VERSION_LOWER_BOUND));
+ VersionRangeBoundingRule upperBoundRule = VersionRangeBoundingRule.valueOf(store.getString(SigilCore.DEFAULT_VERSION_UPPER_BOUND));
+
+ Version version = pe.getVersion();
+ VersionRange versions = VersionRange.newInstance(version, lowerBoundRule, upperBoundRule);
+
+ IPackageImport pi = ModelElementFactory.getInstance().newModelElement(IPackageImport.class);
+ pi.setPackageName(packageName);
+ pi.setVersions(versions);
+
+ return pi;
+ }
+
+ public static Iterable<IJavaElement> findTypes(IParent parent, int... type) throws JavaModelException {
+ LinkedList<IJavaElement> found = new LinkedList<IJavaElement>();
+ scanForElement(parent, type, found, false);
+ return found;
+ }
+
+ public static IJavaElement findType(IParent parent, int... type) throws JavaModelException {
+ LinkedList<IJavaElement> found = new LinkedList<IJavaElement>();
+ scanForElement(parent, type, found, true);
+ return found.isEmpty() ? null : found.getFirst();
+ }
+
+ private static void scanForElement(IParent parent, int[] type, List<IJavaElement> roots, boolean thereCanBeOnlyOne) throws JavaModelException {
+ for ( IJavaElement e : parent.getChildren() ) {
+ if ( isType(type, e) ) {
+ roots.add( e );
+ if ( thereCanBeOnlyOne ) {
+ break;
+ }
+ }
+ else if ( e instanceof IParent ) {
+ scanForElement( (IParent) e, type, roots, thereCanBeOnlyOne );
+ }
+ }
+ }
+
+ private static boolean isType(int[] type, IJavaElement e) {
+ for ( int i : type ) {
+ if ( i == e.getElementType() ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static boolean isAssignableTo(String ifaceOrParentClass, IType type) throws JavaModelException {
+ if ( ifaceOrParentClass == null ) return true;
+
+ ITypeHierarchy h = type.newSupertypeHierarchy(null);
+
+ for ( IType superType : h.getAllClasses() ) {
+ String name = superType.getFullyQualifiedName();
+ if ( name.equals( ifaceOrParentClass ) ) {
+ return true;
+ }
+ }
+ for ( IType ifaceType : h.getAllInterfaces() ) {
+ String name = ifaceType.getFullyQualifiedName();
+ if ( name.equals( ifaceOrParentClass ) ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static IType findType(ITypeRoot root) throws JavaModelException {
+ // TODO Auto-generated method stub
+ for ( IJavaElement child : root.getChildren() ) {
+ if ( child.getElementType() == IJavaElement.TYPE ) {
+ return (IType) child;
+ }
+ }
+
+ throw new JavaModelException( new IllegalStateException( "Missing type for " + root) , IStatus.ERROR );
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/util/ModelHelper.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/util/ModelHelper.java
new file mode 100644
index 0000000..a9f5017
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/util/ModelHelper.java
@@ -0,0 +1,86 @@
+/*
+ * 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.cauldron.sigil.model.util;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.cauldron.sigil.SigilCore;
+import org.cauldron.sigil.model.ICompoundModelElement;
+import org.cauldron.sigil.model.IModelElement;
+import org.cauldron.sigil.model.IModelWalker;
+import org.cauldron.sigil.model.osgi.IBundleModelElement;
+import org.cauldron.sigil.model.osgi.IPackageExport;
+import org.cauldron.sigil.model.osgi.IPackageImport;
+import org.cauldron.sigil.model.osgi.IRequiredBundle;
+
+public class ModelHelper {
+ public static List<IModelElement> findUsers(IModelElement e) {
+ LinkedList<IModelElement> users = new LinkedList<IModelElement>();
+
+ findUsers(e, users);
+
+ return users;
+ }
+
+ private static void findUsers(IModelElement e, final LinkedList<IModelElement> users) {
+ if ( e instanceof IPackageExport ) {
+ final IPackageExport pe = (IPackageExport) e;
+ SigilCore.getGlobalRepositoryManager().visit( new IModelWalker() {
+ public boolean visit(IModelElement element) {
+ if ( element instanceof IPackageImport ) {
+ IPackageImport pi = (IPackageImport) element;
+ if ( pi.accepts( pe ) ) {
+ users.add( pi );
+ }
+ return false;
+ }
+
+ return true;
+ }
+ } );
+ }
+ else if ( e instanceof IBundleModelElement ) {
+ final IBundleModelElement bndl = (IBundleModelElement) e;
+
+ SigilCore.getGlobalRepositoryManager().visit( new IModelWalker() {
+ public boolean visit(IModelElement element) {
+ if ( element instanceof IRequiredBundle ) {
+ IRequiredBundle req = (IRequiredBundle) element;
+ if ( req.accepts( bndl ) ) {
+ users.add( req );
+ }
+ return false;
+ }
+ return true;
+ }
+ } );
+ }
+
+ if ( e instanceof ICompoundModelElement ) {
+ ICompoundModelElement c = (ICompoundModelElement) e;
+ IModelElement[] ch = c.children();
+ for ( IModelElement ee : ch ) {
+ findUsers( ee, users );
+ }
+ }
+ }
+
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/util/ProfileManager.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/util/ProfileManager.java
new file mode 100644
index 0000000..b42287c
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/model/util/ProfileManager.java
@@ -0,0 +1,161 @@
+/*
+ * 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.cauldron.sigil.model.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.regex.Pattern;
+
+import org.cauldron.sigil.SigilCore;
+import org.cauldron.sigil.model.project.ISigilProjectModel;
+import org.cauldron.sigil.utils.GlobCompiler;
+import org.eclipse.core.runtime.Platform;
+import org.osgi.framework.Bundle;
+
+public class ProfileManager {
+ private static final Pattern[] BOOT_DELEGATION_PATTERNS = new Pattern[] {
+ GlobCompiler.compile("org.ietf.jgss"),
+ GlobCompiler.compile("org.omg.*"),
+ GlobCompiler.compile("org.w3c.*"),
+ GlobCompiler.compile("org.xml.*"),
+ GlobCompiler.compile("sun.*"),
+ GlobCompiler.compile("com.sun.*"),
+ };
+
+ private static HashMap<String, Properties> profiles;
+
+ public static boolean isBootDelegate(ISigilProjectModel project, String packageName) {
+ if ( packageName.startsWith( "java." ) ) {
+ return true;
+ }
+
+ for ( Pattern p : BOOT_DELEGATION_PATTERNS ) {
+ if ( p.matcher(packageName).matches()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static Properties findProfileForVersion(String javaVersion) {
+ Map<String, Properties> profiles = loadProfiles();
+
+ if ( "1.5.0".equals( javaVersion ) ) {
+ return profiles.get( "J2SE-1.5" );
+ }
+ else if ( "1.6.0".equals( javaVersion ) ) {
+ return profiles.get( "J2SE-1.6" );
+ }
+
+ return null;
+ }
+
+ private synchronized static Map<String, Properties> loadProfiles() {
+ if ( profiles == null ) {
+ profiles = new HashMap<String, Properties>();
+
+ Bundle b = Platform.getBundle("org.eclipse.osgi");
+
+ for ( String profile : loadProfiles( b )) {
+ if ( profile.trim().length() > 0 ) {
+ URL url = findURL(profile, b);
+ if ( url != null ) {
+ try {
+ Properties p = loadProperties(url);
+ String name = p.getProperty("osgi.java.profile.name");
+ if ( name != null ) {
+ profiles.put(name, p);
+ }
+ else {
+ SigilCore.error( "Invalid profile definition, no name specified: " + url);
+ }
+ } catch (IOException e) {
+ SigilCore.error( "Failed to load java profile", e );
+ }
+ }
+ else {
+ SigilCore.error( "Unknown profile **" + profile + "**" );
+ }
+ }
+ // else ignore empty values
+ }
+ }
+ return profiles;
+ }
+
+ private static String[] loadProfiles(Bundle b) {
+ URL url = findURL("profile.list", b);
+
+ if ( url != null ) {
+ try {
+ Properties p = loadProperties(url);
+ String s = p.getProperty("java.profiles");
+ return s == null ? new String[] {} : s.split(",");
+ } catch (IOException e) {
+ SigilCore.error( "Failed to load java profile list", e );
+ }
+ }
+ else {
+ SigilCore.error( "Failed to find java profile list" );
+ }
+
+ // fine no properties found
+ return new String[] {};
+ }
+
+ @SuppressWarnings("unchecked")
+ private static URL findURL(String file, Bundle b) {
+ Enumeration e = b.findEntries("/", file, false);
+ return e == null ? null : (URL) (e.hasMoreElements() ? e.nextElement() : null);
+ }
+
+
+ private static Properties loadProperties(URL url) throws IOException {
+ Properties p = new Properties();
+
+ InputStream in = null;
+
+ try {
+ in = url.openStream();
+ p.load(in);
+ }
+ finally {
+ if ( in != null ) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+ return p;
+ }
+
+
+
+
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/nature/SigilProjectNature.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/nature/SigilProjectNature.java
new file mode 100644
index 0000000..b425fa2
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/nature/SigilProjectNature.java
@@ -0,0 +1,46 @@
+/*
+ * 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.cauldron.sigil.nature;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectNature;
+import org.eclipse.core.runtime.CoreException;
+
+public class SigilProjectNature implements IProjectNature {
+
+ private IProject project;
+
+ public void configure() throws CoreException {
+ // TODO configure project builder
+
+ }
+
+ public void deconfigure() throws CoreException {
+ }
+
+ public IProject getProject() {
+ return project;
+ }
+
+ public void setProject(IProject project) {
+ this.project = project;
+ }
+
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/preferences/PrefsUtils.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/preferences/PrefsUtils.java
new file mode 100644
index 0000000..0635220
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/preferences/PrefsUtils.java
@@ -0,0 +1,64 @@
+/*
+ * 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.cauldron.sigil.preferences;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.commons.lang.text.StrTokenizer;
+
+public class PrefsUtils {
+
+ private PrefsUtils() {
+ }
+
+ public static final String arrayToString(String[] array) {
+ StringBuilder builder = new StringBuilder();
+
+ for (int i = 0; i < array.length; i++) {
+ if (i > 0)
+ builder.append(',');
+ builder.append(StringEscapeUtils.escapeCsv(array[i]));
+ }
+
+ return builder.toString();
+ }
+
+ public static final String[] stringToArray(String string) {
+ StrTokenizer tokenizer = new StrTokenizer(string, ',', '"');
+ String[] array = new String[tokenizer.size()];
+
+ for (int i = 0; i < array.length; i++) {
+ array[i] = tokenizer.nextToken();
+ }
+
+ return array;
+ }
+
+ public static String listToString(List<String> names) {
+ return arrayToString(names.toArray( new String[names.size()]));
+ }
+
+ public static List<String> stringToList(String string) {
+ return new ArrayList<String>(Arrays.asList(stringToArray(string)));
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/preferences/PromptablePreference.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/preferences/PromptablePreference.java
new file mode 100644
index 0000000..4feb070
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/preferences/PromptablePreference.java
@@ -0,0 +1,24 @@
+/*
+ * 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.cauldron.sigil.preferences;
+
+public enum PromptablePreference {
+ Always, Prompt, Never
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/preferences/SigilPreferencesInitializer.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/preferences/SigilPreferencesInitializer.java
new file mode 100644
index 0000000..6d2e1e2
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/preferences/SigilPreferencesInitializer.java
@@ -0,0 +1,54 @@
+/*
+ * 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.cauldron.sigil.preferences;
+
+
+import org.cauldron.sigil.SigilCore;
+import org.cauldron.sigil.internal.model.repository.RepositoryConfiguration;
+import org.cauldron.sigil.model.common.VersionRangeBoundingRule;
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.jface.preference.IPreferenceStore;
+
+public class SigilPreferencesInitializer extends AbstractPreferenceInitializer {
+
+ public static final String[] EXCLUDED_RESOURCES = new String[] {
+ ".project", ".classpath", ".settings"
+ };
+
+ @Override
+ public void initializeDefaultPreferences() {
+ IPreferenceStore store = SigilCore.getDefault().getPreferenceStore();
+
+ store.setDefault(SigilCore.OSGI_INSTALL_CHECK_PREFERENCE, true);
+
+ store.setDefault(SigilCore.DEFAULT_VERSION_LOWER_BOUND, VersionRangeBoundingRule.Micro.name());
+ store.setDefault(SigilCore.DEFAULT_VERSION_UPPER_BOUND, VersionRangeBoundingRule.Any.name());
+
+ store.setDefault(SigilCore.DEFAULT_EXCLUDED_RESOURCES, PrefsUtils.arrayToString(EXCLUDED_RESOURCES));
+
+ store.setDefault(SigilCore.PREFERENCES_NOASK_OSGI_INSTALL, false);
+
+ store.setDefault(SigilCore.PREFERENCES_ADD_IMPORT_FOR_EXPORT, PromptablePreference.Prompt.name());
+
+ store.setDefault(SigilCore.PREFERENCES_REBUILD_PROJECTS, PromptablePreference.Prompt.name() );
+
+ store.setDefault(RepositoryConfiguration.REPOSITORY_DEFAULT_SET, "org.cauldron.sigil.core.workspaceprovider" );
+ }
+}
diff --git a/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/property/SigilPropertyTester.java b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/property/SigilPropertyTester.java
new file mode 100644
index 0000000..ae85568
--- /dev/null
+++ b/sigil/org.cauldron.sigil.core/src/org/cauldron/sigil/property/SigilPropertyTester.java
@@ -0,0 +1,54 @@
+/*
+ * 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.cauldron.sigil.property;
+
+import org.cauldron.sigil.SigilCore;
+import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+
+public class SigilPropertyTester extends PropertyTester {
+
+ public SigilPropertyTester() {
+ }
+
+ public boolean test( Object receiver, String property, Object[] args, Object expectedValue ) {
+ IResource resource = (IResource) receiver;
+ if ( "isSigilProject".equals( property ) ) {
+ return expectedValue.equals( isSigilProjectLikeResource( resource ) );
+ }
+ return false;
+ }
+
+ /**
+ * @param resource
+ * @return
+ */
+ private static boolean isSigilProjectLikeResource(IResource resource) {
+ if ( resource instanceof IProject ) {
+ IProject p = (IProject) resource;
+ return SigilCore.isSigilProject(p);
+ }
+ else {
+ return resource.getName().equals( SigilCore.SIGIL_PROJECT_FILE );
+ }
+ }
+
+}