You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by ma...@apache.org on 2013/04/02 16:53:35 UTC
svn commit: r1463576 [3/8] - in /ace/trunk:
org.apache.ace.client.repository.api/
org.apache.ace.client.repository.helper.base/
org.apache.ace.client.repository.helper.bundle/
org.apache.ace.client.repository.helper.configuration/
org.apache.ace.client...
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/Artifact2FeatureAssociationRepositoryImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/Artifact2FeatureAssociationRepositoryImpl.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/Artifact2FeatureAssociationRepositoryImpl.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/Artifact2FeatureAssociationRepositoryImpl.java Tue Apr 2 14:53:33 2013
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.repository.impl;
+
+import java.util.Map;
+
+import org.apache.ace.client.repository.object.Artifact2FeatureAssociation;
+import org.apache.ace.client.repository.object.ArtifactObject;
+import org.apache.ace.client.repository.object.FeatureObject;
+import org.apache.ace.client.repository.repository.Artifact2FeatureAssociationRepository;
+import org.osgi.framework.InvalidSyntaxException;
+
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+
+/**
+ * Implementation class for the Artifact2FeatureAssociationRepository. For 'what it does', see Artifact2FeatureAssociationRepository,
+ * for 'how it works', see AssociationRepositoryImpl.
+ */
+public class Artifact2FeatureAssociationRepositoryImpl extends AssociationRepositoryImpl<ArtifactObject, FeatureObject, Artifact2FeatureAssociationImpl, Artifact2FeatureAssociation> implements Artifact2FeatureAssociationRepository {
+ private final static String XML_NODE = "artifacts2features";
+
+ private final ArtifactRepositoryImpl m_artifactRepository;
+ private final FeatureRepositoryImpl m_featureRepository;
+
+ public Artifact2FeatureAssociationRepositoryImpl(ArtifactRepositoryImpl artifactRepository, FeatureRepositoryImpl featureRepository, ChangeNotifier notifier) {
+ super(notifier, XML_NODE);
+ m_artifactRepository = artifactRepository;
+ m_featureRepository = featureRepository;
+ }
+
+ @Override
+ Artifact2FeatureAssociationImpl createNewInhabitant(Map<String, String> attributes) {
+ try {
+ return new Artifact2FeatureAssociationImpl(attributes, this, m_artifactRepository, m_featureRepository);
+ }
+ catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException("Unable to create association: ", e);
+ }
+ }
+
+ @Override
+ Artifact2FeatureAssociationImpl createNewInhabitant(Map<String, String> attributes, Map<String, String> tags) {
+ try {
+ return new Artifact2FeatureAssociationImpl(attributes, tags, this, m_artifactRepository, m_featureRepository);
+ }
+ catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException("Unable to create association: ", e);
+ }
+ }
+
+ @Override
+ Artifact2FeatureAssociationImpl createNewInhabitant(HierarchicalStreamReader reader) {
+ try {
+ return new Artifact2FeatureAssociationImpl(reader, this, m_artifactRepository, m_featureRepository);
+ }
+ catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException("Unable to create association: ", e);
+ }
+ }
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ArtifactObjectImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ArtifactObjectImpl.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ArtifactObjectImpl.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ArtifactObjectImpl.java Tue Apr 2 14:53:33 2013
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.repository.impl;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ace.client.repository.helper.ArtifactHelper;
+import org.apache.ace.client.repository.object.Artifact2FeatureAssociation;
+import org.apache.ace.client.repository.object.ArtifactObject;
+import org.apache.ace.client.repository.object.FeatureObject;
+
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+
+/**
+ * Implementation class for the ArtifactObject. For 'what it does', see ArtifactObject,
+ * for 'how it works', see RepositoryObjectImpl.<br>
+ * <br>
+ * Some functionality of this class is delegated to implementers of {@link ArtifactHelper}.
+ */
+public class ArtifactObjectImpl extends RepositoryObjectImpl<ArtifactObject> implements ArtifactObject {
+ private final static String XML_NODE = "artifact";
+
+ /*
+ * As a general rule, RepositoryObjects do not know about their repository. However, since the Helper
+ * to be used is dictated by the repository, this rule is broken for this class.
+ */
+ private final ArtifactRepositoryImpl m_repo;
+
+ ArtifactObjectImpl(Map<String, String> attributes, String[] mandatoryAttributes, ChangeNotifier notifier, ArtifactRepositoryImpl repo) {
+ super(checkAttributes(attributes, completeMandatoryAttributes(mandatoryAttributes)), notifier, XML_NODE);
+ m_repo = repo;
+ }
+
+ ArtifactObjectImpl(Map<String, String> attributes, String[] mandatoryAttributes, Map<String, String> tags, ChangeNotifier notifier, ArtifactRepositoryImpl repo) {
+ super(checkAttributes(attributes, completeMandatoryAttributes(mandatoryAttributes)), tags, notifier, XML_NODE);
+ m_repo = repo;
+ }
+
+ ArtifactObjectImpl(HierarchicalStreamReader reader, ChangeNotifier notifier, ArtifactRepositoryImpl repo) {
+ super(reader, notifier, XML_NODE);
+ m_repo = repo;
+ }
+
+ private static String[] completeMandatoryAttributes(String[] mandatory) {
+ String[] result = new String[mandatory.length + 1];
+ for (int i = 0; i < mandatory.length; i++) {
+ result[i] = mandatory[i];
+ }
+ result[mandatory.length] = KEY_MIMETYPE;
+ return result;
+ }
+
+ public List<FeatureObject> getFeatures() {
+ return getAssociations(FeatureObject.class);
+ }
+
+ public List<Artifact2FeatureAssociation> getAssociationsWith(FeatureObject feature) {
+ return getAssociationsWith(feature, FeatureObject.class, Artifact2FeatureAssociation.class);
+ }
+
+ @Override
+ public String getAssociationFilter(Map<String, String> properties) {
+ return getHelper().getAssociationFilter(this, properties);
+ }
+
+ @Override
+ public int getCardinality(Map<String, String> properties) {
+ return getHelper().getCardinality(this, properties);
+ }
+
+ @Override
+ public Comparator<ArtifactObject> getComparator() {
+ return getHelper().getComparator();
+ }
+
+ public String getURL() {
+ return getAttribute(KEY_URL);
+ }
+
+ public String getResourceId() {
+ return getAttribute(KEY_RESOURCE_ID);
+ }
+
+ public String getMimetype() {
+ return getAttribute(KEY_MIMETYPE);
+ }
+
+ public String getProcessorPID() {
+ return getAttribute(KEY_PROCESSOR_PID);
+ }
+
+ public void setProcessorPID(String processorPID) {
+ addAttribute(KEY_PROCESSOR_PID, processorPID);
+ }
+
+ public String getName() {
+ return getAttribute(KEY_ARTIFACT_NAME);
+ }
+
+ public String getDescription() {
+ return getAttribute(KEY_ARTIFACT_DESCRIPTION);
+ }
+
+ public void setDescription(String value) {
+ addAttribute(KEY_ARTIFACT_DESCRIPTION, value);
+ }
+
+ @Override
+ String[] getDefiningKeys() {
+ return getHelper().getDefiningKeys().clone();
+ }
+
+ private ArtifactHelper getHelper() {
+ // getMimetype is safe, as is getHelper, and m_repo is final, so no
+ // need to synchronize here...
+ return m_repo.getHelper(getMimetype());
+ }
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ArtifactRepositoryImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ArtifactRepositoryImpl.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ArtifactRepositoryImpl.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ArtifactRepositoryImpl.java Tue Apr 2 14:53:33 2013
@@ -0,0 +1,603 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.repository.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ace.client.repository.RepositoryUtil;
+import org.apache.ace.client.repository.helper.ArtifactHelper;
+import org.apache.ace.client.repository.helper.ArtifactPreprocessor;
+import org.apache.ace.client.repository.helper.ArtifactRecognizer;
+import org.apache.ace.client.repository.helper.ArtifactResource;
+import org.apache.ace.client.repository.helper.bundle.BundleHelper;
+import org.apache.ace.client.repository.object.ArtifactObject;
+import org.apache.ace.client.repository.object.TargetObject;
+import org.apache.ace.client.repository.repository.ArtifactRepository;
+import org.apache.ace.connectionfactory.ConnectionFactory;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+
+/**
+ * Implementation class for the ArtifactRepository. For 'what it does', see ArtifactRepository, for 'how it works', see
+ * ObjectRepositoryImpl.<br>
+ * <br>
+ * This class has some extended functionality when compared to <code>ObjectRepositoryImpl</code>,
+ * <ul>
+ * <li>it keeps track of all <code>ArtifactHelper</code>s, and serves them to its inhabitants.
+ * <li>it handles importing of artifacts.
+ * </ul>
+ */
+public class ArtifactRepositoryImpl extends ObjectRepositoryImpl<ArtifactObjectImpl, ArtifactObject> implements ArtifactRepository {
+ private final static String XML_NODE = "artifacts";
+
+ // Injected by Dependency Manager
+ private volatile BundleContext m_context;
+ private volatile LogService m_log;
+ private volatile ConnectionFactory m_connectionFactory;
+
+ private final Map<String, ArtifactHelper> m_helpers = new HashMap<String, ArtifactHelper>();
+ private URL m_obrBase;
+
+ public ArtifactRepositoryImpl(ChangeNotifier notifier) {
+ super(notifier, XML_NODE);
+ }
+
+ public List<ArtifactObject> getResourceProcessors() {
+ try {
+ return super.get(createFilter("(" + BundleHelper.KEY_RESOURCE_PROCESSOR_PID + "=*)"));
+ }
+ catch (InvalidSyntaxException e) {
+ m_log.log(LogService.LOG_ERROR, "getResourceProcessors' filter returned an InvalidSyntaxException.", e);
+ }
+ return new ArrayList<ArtifactObject>();
+ }
+
+ @Override
+ public List<ArtifactObject> get(Filter filter) {
+ // Note that this excludes any bundle artifacts which are resource processors.
+ try {
+ Filter extendedFilter = createFilter("(&" + filter.toString() + "(!(" + BundleHelper.KEY_RESOURCE_PROCESSOR_PID + "=*)))");
+ return super.get(extendedFilter);
+ }
+ catch (InvalidSyntaxException e) {
+ m_log.log(LogService.LOG_ERROR, "Extending " + filter.toString() + " resulted in an InvalidSyntaxException.", e);
+ }
+ return new ArrayList<ArtifactObject>();
+ }
+
+ @Override
+ public List<ArtifactObject> get() {
+ // Note that this excludes any Bundle artifacts which are resource processors.
+ try {
+ return super.get(createFilter("(!(" + RepositoryUtil.escapeFilterValue(BundleHelper.KEY_RESOURCE_PROCESSOR_PID) + "=*))"));
+ }
+ catch (InvalidSyntaxException e) {
+ m_log.log(LogService.LOG_ERROR, "get's filter returned an InvalidSyntaxException.", e);
+ }
+ return new ArrayList<ArtifactObject>();
+ }
+
+ @Override
+ ArtifactObjectImpl createNewInhabitant(Map<String, String> attributes) {
+ ArtifactHelper helper = getHelper(attributes.get(ArtifactObject.KEY_MIMETYPE));
+ return new ArtifactObjectImpl(helper.checkAttributes(attributes), helper.getMandatoryAttributes(), this, this);
+ }
+
+ @Override
+ ArtifactObjectImpl createNewInhabitant(Map<String, String> attributes, Map<String, String> tags) {
+ ArtifactHelper helper = getHelper(attributes.get(ArtifactObject.KEY_MIMETYPE));
+ ArtifactObjectImpl ao = new ArtifactObjectImpl(helper.checkAttributes(attributes), helper.getMandatoryAttributes(), tags, this, this);
+ if ((ao.getAttribute("upload") != null) && (m_obrBase != null)) {
+ try {
+ ao.addAttribute(ArtifactObject.KEY_URL, new URL(m_obrBase, ao.getDefinition() + ao.getAttribute("upload")).toString());
+ }
+ catch (MalformedURLException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ return ao;
+ }
+
+ @Override
+ ArtifactObjectImpl createNewInhabitant(HierarchicalStreamReader reader) {
+ return new ArtifactObjectImpl(reader, this, this);
+ }
+
+ /**
+ * Helper method for this repository's inhabitants, which finds the necessary helpers.
+ *
+ * @param mimetype
+ * The mimetype for which a helper should be found.
+ * @return An artifact helper for the given mimetype.
+ * @throws IllegalArgumentException
+ * when the mimetype is invalid, or no helpers are available.
+ */
+ ArtifactHelper getHelper(String mimetype) {
+ synchronized (m_helpers) {
+ if ((mimetype == null) || (mimetype.length() == 0)) {
+ throw new IllegalArgumentException("Without a mimetype, we cannot find a helper.");
+ }
+
+ ArtifactHelper helper = m_helpers.get(mimetype.toLowerCase());
+
+ if (helper == null) {
+ throw new IllegalArgumentException("There are no ArtifactHelpers known for type '" + mimetype + "'.");
+ }
+
+ return helper;
+ }
+ }
+
+ /**
+ * Method intended for adding artifact helpers by the bundle's activator.
+ */
+ void addHelper(String mimetype, ArtifactHelper helper) {
+ synchronized (m_helpers) {
+ if ((mimetype == null) || (mimetype.length() == 0)) {
+ m_log.log(LogService.LOG_WARNING, "An ArtifactHelper has been published without a proper mimetype.");
+ }
+ else {
+ m_helpers.put(mimetype.toLowerCase(), helper);
+ }
+ }
+ }
+
+ /**
+ * Method intended for removing artifact helpers by the bundle's activator.
+ */
+ void removeHelper(String mimetype, ArtifactHelper helper) {
+ synchronized (m_helpers) {
+ if ((mimetype == null) || (mimetype.length() == 0)) {
+ m_log.log(LogService.LOG_WARNING, "An ArtifactHelper is being removed without a proper mimetype.");
+ }
+ else {
+ m_helpers.remove(mimetype.toLowerCase());
+ }
+ }
+ }
+
+ /**
+ * Utility function that takes either a URL or a String representing a mimetype, and returns the corresponding
+ * <code>ArtifactHelper</code>, <code>ArtifactRecognizer</code> and, if not specified, the mimetype.
+ *
+ * @param input
+ * Either a <code>URL</code> pointing to a physical artifact, or a <code>String</code> representing a
+ * mime type.
+ * @return A mapping from a class (<code>ArtifactRecognizer</code>, <code>ArtifactHelper</code> or
+ * <code>String</code> to an instance of that class as a result.
+ */
+ protected Map<Class<?>, Object> findRecognizerAndHelper(Object input) throws IllegalArgumentException {
+ // check input.
+ URL url = null;
+ String mimetype = null;
+ if (input instanceof URL) {
+ url = (URL) input;
+ }
+ else if (input instanceof String) {
+ mimetype = (String) input;
+ }
+ else {
+ throw new IllegalArgumentException("findRecognizer received an unrecognized input.");
+ }
+
+ // Get all published ArtifactRecognizers.
+ ServiceReference[] refs = null;
+ try {
+ refs = m_context.getServiceReferences(ArtifactRecognizer.class.getName(), null);
+ }
+ catch (InvalidSyntaxException e) {
+ // We do not pass in a filter, so this should not happen.
+ m_log.log(LogService.LOG_WARNING, "A null filter resulted in an InvalidSyntaxException from getServiceReferences.");
+ }
+
+ if (refs == null) {
+ throw new IllegalArgumentException("There are no artifact recognizers available.");
+ }
+
+ // If available, sort the references by service ranking.
+ Arrays.sort(refs, SERVICE_RANK_COMPARATOR);
+
+ ArtifactResource resource = convertToArtifactResource(url);
+
+ // Check all referenced services to find one that matches our input.
+ ArtifactRecognizer recognizer = null;
+ String foundMimetype = null;
+ for (ServiceReference ref : refs) {
+ ArtifactRecognizer candidate = (ArtifactRecognizer) m_context.getService(ref);
+ try {
+ if (mimetype != null) {
+ if (candidate.canHandle(mimetype)) {
+ recognizer = candidate;
+ break;
+ }
+ }
+ else {
+ String candidateMime = candidate.recognize(resource);
+ if (candidateMime != null) {
+ foundMimetype = candidateMime;
+ recognizer = candidate;
+ break;
+ }
+ }
+ }
+ finally {
+ m_context.ungetService(ref);
+ }
+ }
+
+ if (recognizer == null) {
+ throw new IllegalArgumentException("There is no artifact recognizer that recognizes artifact " + ((mimetype != null) ? mimetype : url));
+ }
+
+ // Package the results in the map.
+ Map<Class<?>, Object> result = new HashMap<Class<?>, Object>();
+ result.put(ArtifactRecognizer.class, recognizer);
+ if (mimetype == null) {
+ result.put(ArtifactHelper.class, getHelper(foundMimetype));
+ result.put(String.class, foundMimetype);
+ }
+ else {
+ result.put(ArtifactHelper.class, getHelper(mimetype));
+ }
+
+ return result;
+ }
+
+ public boolean recognizeArtifact(URL artifact) {
+ try {
+ Map<Class<?>, Object> fromArtifact = findRecognizerAndHelper(artifact);
+ String mimetype = (String) fromArtifact.get(String.class);
+ return mimetype != null;
+ }
+ catch (Exception e) {
+ // too bad... Nothing to do now.
+ return false;
+ }
+ }
+
+ public ArtifactObject importArtifact(URL artifact, boolean upload) throws IllegalArgumentException, IOException {
+ try {
+ if ((artifact == null) || (artifact.toString().length() == 0)) {
+ throw new IllegalArgumentException("The URL to import cannot be null or empty.");
+ }
+ checkURL(artifact);
+
+ Map<Class<?>, Object> fromArtifact = findRecognizerAndHelper(artifact);
+ ArtifactRecognizer recognizer = (ArtifactRecognizer) fromArtifact.get(ArtifactRecognizer.class);
+ ArtifactHelper helper = (ArtifactHelper) fromArtifact.get(ArtifactHelper.class);
+ String mimetype = (String) fromArtifact.get(String.class);
+
+ return importArtifact(artifact, recognizer, helper, mimetype, false, upload);
+ }
+ catch (IllegalArgumentException iae) {
+ m_log.log(LogService.LOG_INFO, "Error importing artifact: " + iae.getMessage());
+ throw iae;
+ }
+ catch (IOException ioe) {
+ m_log.log(LogService.LOG_INFO, "Error storing artifact: " + ioe.getMessage());
+ throw ioe;
+ }
+ }
+
+ public ArtifactObject importArtifact(URL artifact, String mimetype, boolean upload) throws IllegalArgumentException, IOException {
+ try {
+ if ((artifact == null) || (artifact.toString().length() == 0)) {
+ throw new IllegalArgumentException("The URL to import cannot be null or empty.");
+ }
+ if ((mimetype == null) || (mimetype.length() == 0)) {
+ throw new IllegalArgumentException("The mimetype of the artifact to import cannot be null or empty.");
+ }
+
+ checkURL(artifact);
+
+ Map<Class<?>, Object> fromMimetype = findRecognizerAndHelper(mimetype);
+ ArtifactRecognizer recognizer = (ArtifactRecognizer) fromMimetype.get(ArtifactRecognizer.class);
+ ArtifactHelper helper = (ArtifactHelper) fromMimetype.get(ArtifactHelper.class);
+
+ return importArtifact(artifact, recognizer, helper, mimetype, true, upload);
+ }
+ catch (IllegalArgumentException iae) {
+ m_log.log(LogService.LOG_INFO, "Error importing artifact: " + iae.getMessage());
+ throw iae;
+ }
+ catch (IOException ioe) {
+ m_log.log(LogService.LOG_INFO, "Error storing artifact: " + ioe.getMessage());
+ throw ioe;
+ }
+ }
+
+ private ArtifactObject importArtifact(URL artifact, ArtifactRecognizer recognizer, ArtifactHelper helper, String mimetype, boolean overwrite, boolean upload) throws IOException {
+ ArtifactResource resource = convertToArtifactResource(artifact);
+
+ Map<String, String> attributes = recognizer.extractMetaData(resource);
+ Map<String, String> tags = new HashMap<String, String>();
+
+ helper.checkAttributes(attributes);
+ attributes.put(ArtifactObject.KEY_ARTIFACT_DESCRIPTION, "");
+ if (overwrite) {
+ attributes.put(ArtifactObject.KEY_MIMETYPE, mimetype);
+ }
+
+ String artifactURL = artifact.toString();
+
+ attributes.put(ArtifactObject.KEY_URL, artifactURL);
+
+ if (upload) {
+ attributes.put("upload", recognizer.getExtension(resource));
+ }
+
+ ArtifactObject result = create(attributes, tags);
+
+ if (upload) {
+ try {
+ upload(artifact, result.getDefinition() + attributes.get("upload"), mimetype);
+ }
+ catch (IOException ex) {
+ remove(result);
+ throw ex;
+ }
+ finally {
+ try {
+ attributes.remove("upload");
+ }
+ catch (Exception ex) {
+ // Not much we can do
+ }
+ }
+ }
+ return result;
+
+ }
+
+ /**
+ * Helper method which checks a given URL for 'validity', that is, does this URL point to something that can be
+ * read.
+ *
+ * @param artifact
+ * A URL pointing to an artifact.
+ * @throws IllegalArgumentException
+ * when the URL does not point to a valid file.
+ */
+
+ private void checkURL(URL artifact) throws IllegalArgumentException {
+ // First, check whether we can actually reach something from this URL.
+ InputStream is = null;
+ try {
+ is = openInputStream(artifact);
+ }
+ catch (IOException ioe) {
+ throw new IllegalArgumentException("Artifact " + artifact + " does not point to a valid file.");
+ }
+ finally {
+ if (is != null) {
+ try {
+ is.close();
+ }
+ catch (IOException ioe) {
+ // Too bad, nothing to do.
+ }
+ }
+ }
+
+ // Then, check whether the name is legal.
+ String artifactName = artifact.toString();
+ for (byte b : artifactName.substring(artifactName.lastIndexOf('/') + 1).getBytes()) {
+ if (!(((b >= 'A') && (b <= 'Z')) || ((b >= 'a') && (b <= 'z')) || ((b >= '0') && (b <= '9')) || (b == '.') || (b == '-') || (b == '_'))) {
+ throw new IllegalArgumentException("Artifact " + artifactName + "'s name contains an illegal character '" + new String(new byte[] { b }) + "'");
+ }
+ }
+ }
+
+ /**
+ * Uploads an artifact to the OBR.
+ *
+ * @param artifact
+ * URL pointing to the local artifact.
+ * @param mimetype
+ * The mimetype of this artifact.
+ * @return The persistent URL of this artifact.
+ * @throws IOException
+ * for any problem uploading the artifact.
+ */
+ private URL upload(URL artifact, String definition, String mimetype) throws IOException {
+ if (m_obrBase == null) {
+ throw new IOException("There is no storage available for this artifact.");
+ }
+
+ InputStream input = null;
+ OutputStream output = null;
+ URL url = null;
+ try {
+ input = openInputStream(artifact);
+
+ url = new URL(m_obrBase, definition);
+
+ URLConnection connection = m_connectionFactory.createConnection(url);
+
+ connection.setDoOutput(true);
+ connection.setDoInput(true);
+ connection.setUseCaches(false);
+
+ connection.setRequestProperty("Content-Type", mimetype);
+ if (connection instanceof HttpURLConnection) {
+ // ACE-294: enable streaming mode causing only small amounts of memory to be
+ // used for this commit. Otherwise, the entire input stream is cached into
+ // memory prior to sending it to the server...
+ ((HttpURLConnection) connection).setChunkedStreamingMode(8192);
+ }
+
+ output = connection.getOutputStream();
+
+ byte[] buffer = new byte[4 * 1024];
+ for (int count = input.read(buffer); count != -1; count = input.read(buffer)) {
+ output.write(buffer, 0, count);
+ }
+
+ output.close();
+
+ if (connection instanceof HttpURLConnection) {
+ int responseCode = ((HttpURLConnection) connection).getResponseCode();
+ switch (responseCode) {
+ case HttpURLConnection.HTTP_OK:
+ break;
+ case HttpURLConnection.HTTP_CONFLICT:
+ throw new IOException("Artifact already exists in storage.");
+ case HttpURLConnection.HTTP_INTERNAL_ERROR:
+ throw new IOException("The storage server returned an internal server error.");
+ default:
+ throw new IOException("The storage server returned code " + responseCode + " writing to " + url.toString());
+ }
+ }
+ }
+ catch (IOException ioe) {
+ throw new IOException("Error importing artifact " + artifact.toString() + ": " + ioe.getMessage());
+ }
+ finally {
+ if (input != null) {
+ try {
+ input.close();
+ }
+ catch (Exception ex) {
+ // Not much we can do
+ }
+ }
+ if (output != null) {
+ try {
+ output.close();
+ }
+ catch (Exception ex) {
+ // Not much we can do
+ }
+ }
+ }
+
+ return url;
+ }
+
+ public void setObrBase(URL obrBase) {
+ m_obrBase = obrBase;
+ }
+
+ public String preprocessArtifact(ArtifactObject artifact, TargetObject target, String targetID, String version) throws IOException {
+ ArtifactPreprocessor preprocessor = getHelper(artifact.getMimetype()).getPreprocessor();
+ if (preprocessor == null) {
+ return artifact.getURL();
+ }
+ else {
+ return preprocessor.preprocess(artifact.getURL(), new TargetPropertyResolver(target), targetID, version, m_obrBase);
+ }
+ }
+
+ public boolean needsNewVersion(ArtifactObject artifact, TargetObject target, String targetID, String fromVersion) {
+ ArtifactPreprocessor preprocessor = getHelper(artifact.getMimetype()).getPreprocessor();
+ if (preprocessor == null) {
+ return false;
+ }
+ else {
+ return preprocessor.needsNewVersion(artifact.getURL(), new TargetPropertyResolver(target), targetID, fromVersion);
+ }
+ }
+
+ public URL getObrBase() {
+ return m_obrBase;
+ }
+
+ /**
+ * Custom comparator which sorts service references by service rank, highest rank first.
+ */
+ private static Comparator<ServiceReference> SERVICE_RANK_COMPARATOR = new Comparator<ServiceReference>() { // TODO
+ // ServiceReferences
+ // are
+ // comparable
+ // by
+ // default
+ // now
+ public int compare(ServiceReference o1, ServiceReference o2) {
+ int rank1 = 0;
+ int rank2 = 0;
+ try {
+ Object rankObject1 = o1.getProperty(Constants.SERVICE_RANKING);
+ rank1 = (rankObject1 == null) ? 0 : ((Integer) rankObject1).intValue();
+ }
+ catch (ClassCastException cce) {
+ // No problem.
+ }
+ try {
+ Object rankObject2 = o2.getProperty(Constants.SERVICE_RANKING);
+ rank1 = (rankObject2 == null) ? 0 : ((Integer) rankObject2).intValue();
+ }
+ catch (ClassCastException cce) {
+ // No problem.
+ }
+
+ return rank1 - rank2;
+ }
+ };
+
+ private InputStream openInputStream(URL artifactURL) throws IOException {
+ URLConnection connection = m_connectionFactory.createConnection(artifactURL);
+ return connection.getInputStream();
+ }
+
+ /**
+ * Converts a given URL to a {@link ArtifactResource} that abstracts the way we access the contents of the URL away
+ * from the URL itself. This way, we can avoid having to pass authentication credentials, or a
+ * {@link ConnectionFactory} to the artifact recognizers.
+ *
+ * @param url
+ * the URL to convert, can be <code>null</code> in which case <code>null</code> is returned.
+ * @return an {@link ArtifactResource}, or <code>null</code> if the given URL was <code>null</code>.
+ */
+ private ArtifactResource convertToArtifactResource(final URL url) {
+ if (url == null) {
+ return null;
+ }
+
+ return new ArtifactResource() {
+ public URL getURL() {
+ return url;
+ }
+
+ public InputStream openStream() throws IOException {
+ // Take care of the fact that an URL could need credentials to be accessible!!!
+ URLConnection conn = m_connectionFactory.createConnection(getURL());
+ conn.setUseCaches(true);
+ return conn.getInputStream();
+ }
+ };
+ }
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/AssociationImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/AssociationImpl.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/AssociationImpl.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/AssociationImpl.java Tue Apr 2 14:53:33 2013
@@ -0,0 +1,250 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.repository.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.ace.client.repository.Associatable;
+import org.apache.ace.client.repository.Association;
+import org.apache.ace.client.repository.RepositoryObject;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.event.Event;
+
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+
+/**
+ * A basic implementation of the Association interface. Implements 'common' behavior for all associations.
+ *
+ * The association allows up to m-to-n associations. Each end of the association gets
+ * a filter to match objects, possibly a cardinality (if no cardinality is specified,
+ * 1 is assumed), and, if there can be more matches to the filter than the given cardinality,
+ * a comparator should be provided in the constructor.
+ *
+ * @param <L> The type of the RepositoryObject on the left side of this association
+ * @param <R> The type of the RepositoryObject on the right side of this association
+ * @param <T> The non-generic Association interface this object should use.
+ */
+public class AssociationImpl<L extends RepositoryObject, R extends RepositoryObject, T extends Association<L, R>> extends RepositoryObjectImpl<T> implements Association<L, R> {
+
+ /* These lists are volatile, since we use copy-on-write semantics for
+ * updating them.
+ */
+ private volatile List<L> m_left = new ArrayList<L>();
+ private volatile List<R> m_right = new ArrayList<R>();
+ private final Object m_lock = new Object();
+
+ private final Filter m_filterLeft;
+ private final Filter m_filterRight;
+
+ private final ObjectRepositoryImpl<?, L> m_leftRepository;
+ private final ObjectRepositoryImpl<?, R> m_rightRepository;
+ private final Class<L> m_leftClass;
+ private final Class<R> m_rightClass;
+
+ /**
+ * Constructor intended for deserialization. For most parameters, see below.
+ * @param reader a stream reader which contains an XML representation of this object's contents.
+ */
+ public AssociationImpl(HierarchicalStreamReader reader, ChangeNotifier notifier, Class<L> leftClass, Class<R> rightClass, Comparator<L> leftComparator, Comparator<R> rightComparator, ObjectRepositoryImpl<?, L> leftRepository, ObjectRepositoryImpl<?, R> rightRepository, String xmlNode) throws InvalidSyntaxException {
+ this(readMap(reader), notifier, leftClass, rightClass, leftRepository, rightRepository, xmlNode);
+ }
+
+ /**
+ * Basic constructor for AssociationImpl.
+ * @param attributes A map of attributes. This should at least contain <code>Association.LEFT_ENDPOINT</code> and <code>Association.RIGHT_ENDPOINT</code>,
+ * and optionally <code>Association.LEFT_CARDINALITY</code> and <code>Association.RIGHT_CARDINALITY</code>.
+ * @param notifier An instance of the event admin
+ * @param leftClass The class on the left side of this association.
+ * @param rightClass The class on the right side of this association.
+ * @param leftRepository The repository which holds object of <code>leftClass</code>.
+ * @param rightRepository The repository which holds object of <code>rightClass</code>.
+ * @param xmlNode The tag by which this object is known in the XML representation.
+ * @throws InvalidSyntaxException Thrown when the attributes contain an invalidly constructed filter string.
+ */
+ public AssociationImpl(Map<String, String> attributes, ChangeNotifier notifier, Class<L> leftClass, Class<R> rightClass, ObjectRepositoryImpl<?, L> leftRepository, ObjectRepositoryImpl<?, R> rightRepository, String xmlNode) throws InvalidSyntaxException {
+ super(attributes, notifier, xmlNode);
+
+ if ((getAttribute(LEFT_CARDINALITY) != null) && (Integer.parseInt(getAttribute(LEFT_CARDINALITY)) < 1)) {
+ throw new IllegalArgumentException("The left cardinality should be 1 or greater.");
+ }
+ if ((getAttribute(RIGHT_CARDINALITY) != null) && (Integer.parseInt(getAttribute(RIGHT_CARDINALITY)) < 1)) {
+ throw new IllegalArgumentException("The right cardinality should be 1 or greater.");
+ }
+
+ m_leftClass = leftClass;
+ m_rightClass = rightClass;
+ m_leftRepository = leftRepository;
+ m_rightRepository = rightRepository;
+
+ m_filterLeft = m_leftRepository.createFilter(getAttribute(Association.LEFT_ENDPOINT));
+ m_filterRight = m_rightRepository.createFilter(getAttribute(Association.RIGHT_ENDPOINT));
+
+ locateLeftEndpoint(false);
+ locateRightEndpoint(false);
+ }
+
+ public AssociationImpl(Map<String, String> attributes, Map<String, String> tags, ChangeNotifier notifier, Class<L> leftClass, Class<R> rightClass, ObjectRepositoryImpl<?, L> leftRepository, ObjectRepositoryImpl<?, R> rightRepository, String xmlNode) throws InvalidSyntaxException {
+ super(attributes, tags, notifier, xmlNode);
+
+ if ((getAttribute(LEFT_CARDINALITY) != null) && (Integer.parseInt(getAttribute(LEFT_CARDINALITY)) < 1)) {
+ throw new IllegalArgumentException("The left cardinality should be 1 or greater.");
+ }
+ if ((getAttribute(RIGHT_CARDINALITY) != null) && (Integer.parseInt(getAttribute(RIGHT_CARDINALITY)) < 1)) {
+ throw new IllegalArgumentException("The right cardinality should be 1 or greater.");
+ }
+
+ m_leftClass = leftClass;
+ m_rightClass = rightClass;
+ m_leftRepository = leftRepository;
+ m_rightRepository = rightRepository;
+
+ m_filterLeft = m_leftRepository.createFilter(getAttribute(Association.LEFT_ENDPOINT));
+ m_filterRight = m_rightRepository.createFilter(getAttribute(Association.RIGHT_ENDPOINT));
+
+ locateLeftEndpoint(false);
+ locateRightEndpoint(false);
+ }
+
+ public List<Associatable> getTo(Associatable from) {
+ if (m_left.contains(from)) {
+ return new ArrayList<Associatable>(m_right);
+ }
+ if (m_right.contains(from)) {
+ return new ArrayList<Associatable>(m_left);
+ }
+ return null;
+ }
+
+ public List<L> getLeft() {
+ return new ArrayList<L>(m_left);
+ }
+
+ public List<R> getRight() {
+ return new ArrayList<R>(m_right);
+ }
+
+ public void remove() {
+ for (L l : m_left) {
+ l.remove(this, m_rightClass);
+ }
+ for (R r : m_right) {
+ r.remove(this, m_leftClass);
+ }
+ }
+
+ /**
+ * Locates the most suited endpoint of one side of this association. If the corresponding filter
+ * matches multiple objects, the <code>comparator</code> will be used to find the most suited one.
+ * The association will register itself with a new endpoint, and remove itself from the old one.
+ * @param <TYPE> (only used for type matching).
+ * @param objectRepositoryImpl The repository where the endpoint should come from.
+ * @param filter A filter string, used to get candidate-endpoints from <code>objectRepositoryImpl</code>.
+ * @param endpoint The current endpoint.
+ * @param comparator A comparator, used when there are multiple potential endpoints.
+ * @param clazz The class of the 'other side' of this association.
+ * @return The most suited endpoint; this could be equal to <code>endpoint</code>.
+ */
+ @SuppressWarnings("unchecked")
+ private <TYPE extends RepositoryObject> List<TYPE> locateEndpoint(ObjectRepositoryImpl<?, TYPE> objectRepositoryImpl, Filter filter, List<TYPE> endpoints, int cardinality, Class<? extends RepositoryObject> clazz, boolean notify) {
+ List<TYPE> candidates = objectRepositoryImpl.get(filter);
+ List<TYPE> newEndpoints = new ArrayList<TYPE>();
+ List<TYPE> oldEndpoints = new ArrayList<TYPE>(endpoints);
+
+ if (candidates.size() > cardinality) {
+ Comparator<TYPE> comparator = candidates.get(0).getComparator();
+ if (comparator != null) {
+ Collections.sort(candidates, comparator);
+ }
+ else {
+ throw new NullPointerException("Filter '" + filter.toString() + "' has resulted in multiple candidates, so the RepositoryObject descendents should have provide a comparator, which they do not.");
+ }
+ }
+
+ for (int i = 0; (i < cardinality) && !candidates.isEmpty(); i++) {
+ TYPE current = candidates.remove(0);
+ newEndpoints.add(current);
+
+ if (!oldEndpoints.remove(current)) {
+ current.add(this, clazz);
+ }
+ }
+
+ for (TYPE e : oldEndpoints) {
+ e.remove(this, clazz);
+ }
+
+ if (!endpoints.equals(newEndpoints)) {
+ Properties props = new Properties();
+ props.put(EVENT_OLD, new ArrayList<TYPE>(endpoints));
+ props.put(EVENT_NEW, new ArrayList<TYPE>(newEndpoints));
+ if (notify) {
+ notifyChanged(props);
+ }
+ }
+
+ return newEndpoints;
+ }
+
+ /**
+ * Locates the left endpoint by using the generic locateEndpoint and notifies
+ * listeners of changes, if any.
+ * @param notify Indicates whether notifications should be sent out.
+ */
+ private void locateLeftEndpoint(boolean notify) {
+ synchronized (m_lock) {
+ m_left = locateEndpoint(m_leftRepository, m_filterLeft, m_left, (getAttribute(LEFT_CARDINALITY) == null ? 1 : Integer.parseInt(getAttribute(LEFT_CARDINALITY))), m_rightClass, notify);
+ }
+ }
+
+ /**
+ * Locates the right endpoint by using the generic locateEndpoint and notifies
+ * listeners of changes, if any.
+ * @param notify Indicates whether notifications should be sent out.
+ */
+ private void locateRightEndpoint(boolean notify) {
+ synchronized (m_lock) {
+ m_right = locateEndpoint(m_rightRepository, m_filterRight, m_right, (getAttribute(RIGHT_CARDINALITY) == null ? 1 : Integer.parseInt(getAttribute(RIGHT_CARDINALITY))), m_leftClass, notify);
+ }
+ }
+
+ public boolean isSatisfied() {
+ return (!m_left.isEmpty()) && (!m_right.isEmpty());
+ }
+
+ @Override
+ public void handleEvent(Event event) {
+ // We get a topic which ends in '/*', but the event contains a specialized topic.
+ // for now, we chop of the star, and check whether the topic starts with that.
+ RepositoryObject entity = (RepositoryObject) event.getProperty(RepositoryObject.EVENT_ENTITY);
+ if ((event.getTopic().endsWith("ADDED")) || event.getTopic().endsWith("REMOVED")) {
+ if (m_leftClass.isInstance(entity) && m_filterLeft.match(entity.getDictionary())) {
+ locateLeftEndpoint(true);
+ }
+ if (m_rightClass.isInstance(entity) && m_filterRight.match(entity.getDictionary())) {
+ locateRightEndpoint(true);
+ }
+ }
+ }
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/AssociationRepositoryImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/AssociationRepositoryImpl.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/AssociationRepositoryImpl.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/AssociationRepositoryImpl.java Tue Apr 2 14:53:33 2013
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.repository.impl;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ace.client.repository.Association;
+import org.apache.ace.client.repository.AssociationRepository;
+import org.apache.ace.client.repository.RepositoryObject;
+
+
+/**
+ * A basic association repository. It cannot be directly instantiated, since some functionality
+ * is delagated to deriving classes, being
+ * <bl>
+ * <li>The creation of new inhabitants</li>
+ * <li>The generation of filter strings based on objects</li>
+ * </bl>
+ *
+ * @param <L> The left side of the associations which will be stored in this repository.
+ * @param <R> The right side of the associations which will be stored in this repository.
+ * @param <I> An implementation of the association from <code>L</code> to <code>R</code>.
+ * @param <T> The non-generic Association interface that <code>I</code> implements.
+ */
+public abstract class AssociationRepositoryImpl<L extends RepositoryObject, R extends RepositoryObject, I extends AssociationImpl<L, R, T>, T extends Association<L, R>> extends ObjectRepositoryImpl<I, T> implements AssociationRepository<L, R, T> {
+ private Object m_lock = new Object();
+
+ public AssociationRepositoryImpl(ChangeNotifier notifier, String xmlNode) {
+ super(notifier, xmlNode);
+ }
+
+ @SuppressWarnings("unchecked")
+ public T create(String left, int leftCardinality, String right, int rightCardinality) {
+ synchronized (m_lock) {
+ T association = null;
+ try {
+ Map<String, String> attributes = new HashMap<String, String>();
+ attributes.put(Association.LEFT_ENDPOINT, left);
+ attributes.put(Association.RIGHT_ENDPOINT, right);
+ attributes.put(Association.LEFT_CARDINALITY, "" + leftCardinality);
+ attributes.put(Association.RIGHT_CARDINALITY, "" + rightCardinality);
+ association = (T) createNewInhabitant(attributes);
+ add(association);
+ }
+ catch (Exception e) {
+ // We have not been able to instantiate our constructor. Not much to do about that.
+ e.printStackTrace();
+ }
+ return association;
+ }
+ }
+
+ public T create(String left, String right) {
+ return create(left, Integer.MAX_VALUE, right, Integer.MAX_VALUE);
+ }
+
+ public T create(L left, Map<String, String> leftProps, R right, Map<String, String> rightProps) {
+ return create(left.getAssociationFilter(leftProps), left.getCardinality(leftProps),
+ right.getAssociationFilter(rightProps), right.getCardinality(rightProps));
+ }
+
+ public T create(L left, R right) {
+ return create(left, null, right, null);
+ }
+
+ public T create(List<L> left, List<R> right) {
+ if ((left == null) || left.isEmpty()) {
+ throw new IllegalArgumentException("The left side of the association cannot be empty.");
+ }
+ if ((right == null) || right.isEmpty()) {
+ throw new IllegalArgumentException("The right side of the association cannot be empty.");
+ }
+
+ StringBuilder leftFilter = new StringBuilder("(|");
+ for (L l : left) {
+ leftFilter.append(l.getAssociationFilter(null));
+ }
+ leftFilter.append(")");
+
+ StringBuilder rightFilter = new StringBuilder("(|");
+ for (R r : right) {
+ rightFilter.append(r.getAssociationFilter(null));
+ }
+ rightFilter.append(")");
+
+ return create(leftFilter.toString(), Integer.MAX_VALUE, rightFilter.toString(), Integer.MAX_VALUE);
+ }
+
+ @Override
+ public void remove(T entity) {
+ synchronized (m_lock) {
+ super.remove(entity);
+ entity.remove();
+ }
+ }
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ChangeNotifier.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ChangeNotifier.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ChangeNotifier.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ChangeNotifier.java Tue Apr 2 14:53:33 2013
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.repository.impl;
+
+import java.util.Properties;
+
+/**
+ * This interface defines a mechanism for notifying both internally interested parties, and
+ * external listeners, of changes to the a given 'inhabitant' of the model.
+ */
+public interface ChangeNotifier {
+ /**
+ * Notifies both internal and external listeners of a change to some object.
+ * @param topic A topic, as defined in the interface definitions of the various objects.
+ * Note that this is not a <i>full</i> topic, but merely the 'last part', such as "ADDED";
+ * this allows the ChangeNotifier to generate internal or external topics.
+ * @param props Properties to pack with the event. May be null.
+ */
+ public void notifyChanged(String topic, Properties props);
+
+ /**
+ * Notifies both internal and external listeners of a change to some object.
+ * @param topic A topic, as defined in the interface definitions of the various objects.
+ * Note that this is not a <i>full</i> topic, but merely the 'last part', such as "ADDED";
+ * this allows the ChangeNotifier to generate internal or external topics.
+ * @param props Properties to pack with the event. May be null.
+ * @param internalOnly Indicates this event is only for internal use, and the external
+ * events should not be sent.
+ */
+ public void notifyChanged(String topic, Properties props, boolean internalOnly);
+
+ /**
+ * Gets a topic name which allows subscription to all topics that this ChangeNotifier can send.
+ * @param publicTopic Indicates whether we are interested in the public (<code>true</code>) or the
+ * private topic (<code>false</code>).
+ * @return A topic name.
+ */
+ String getTopicAll(boolean publicTopic);
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ChangeNotifierImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ChangeNotifierImpl.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ChangeNotifierImpl.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ChangeNotifierImpl.java Tue Apr 2 14:53:33 2013
@@ -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.apache.ace.client.repository.impl;
+
+import java.util.Dictionary;
+import java.util.Properties;
+
+import org.apache.ace.client.repository.SessionFactory;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+
+/**
+ * ChangeNotifierImpl provides a basic implementation of a ChangeNotifier, intended to be used
+ * by classes related to the RepositoryAdmin.<br>
+ * <br>
+ * Topics are built up in the following fashion:
+ * <ul>
+ * <li><b>...TopicRoot</b> All topics start with a TopicRoot, which is the same for all related classes, and ends with a "/".
+ * There can be internal and external topics, hence two TopicRoot parameters in the constructor.</li>
+ * <li><b>entityRoot</b> This is followed by a class-specific root, usually consisting of the classname with an added "/".</li>
+ * <li>Finally, for each call to <code>notifyChanged</code>, a topic can be specified, which is something like
+ * "CHANGED" or "ADDED".</li>
+ * </ul>
+ */
+public class ChangeNotifierImpl implements ChangeNotifier {
+
+ private final EventAdmin m_eventAdmin;
+ private final String m_privateTopicRoot;
+ private final String m_publicTopicRoot;
+ private final String m_entityRoot;
+ private final String m_sessionID;
+
+ /**
+ * Creates a new ChangeNotifierImpl.
+ * @param eventAdmin An EventAdmin to send events to.
+ * @param privateTopicRoot The root of all private topics; see TopicRoot in the description of this class.
+ * @param publicTopicRoot The root of all public topics; see TopicRoot in the description of this class.
+ * @param entityRoot A class-specific root for the class which will use this ChangeNotifierImpl.
+ */
+ ChangeNotifierImpl(EventAdmin eventAdmin, String privateTopicRoot, String publicTopicRoot, String entityRoot, String sessionID) {
+ m_eventAdmin = eventAdmin;
+ m_privateTopicRoot = privateTopicRoot;
+ m_publicTopicRoot = publicTopicRoot;
+ m_entityRoot = entityRoot;
+ m_sessionID = sessionID;
+ }
+
+ private Properties addSession(Properties props) {
+ if (props == null) {
+ props = new Properties();
+ }
+ props.put(SessionFactory.SERVICE_SID, m_sessionID);
+ return props;
+ }
+
+ public void notifyChanged(String topic, Properties props, boolean internalOnly) {
+ props = addSession(props);
+ m_eventAdmin.sendEvent(new Event(m_privateTopicRoot + m_entityRoot + topic,(Dictionary) props));
+ if (!internalOnly) {
+ m_eventAdmin.postEvent(new Event(m_publicTopicRoot + m_entityRoot + topic, (Dictionary) props));
+ }
+ }
+
+ public void notifyChanged(String topic, Properties props) {
+ notifyChanged(topic, props, false);
+ }
+
+ public String getTopicAll(boolean publicTopic) {
+ if (publicTopic) {
+ return m_publicTopicRoot + m_entityRoot + "*";
+ }
+ else {
+ return m_privateTopicRoot + m_entityRoot + "*";
+ }
+ }
+
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ChangeNotifierManager.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ChangeNotifierManager.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ChangeNotifierManager.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ChangeNotifierManager.java Tue Apr 2 14:53:33 2013
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.repository.impl;
+
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+
+/**
+ * ChangeNotifierManager handles a number of ChangeNotifiers, so there is only
+ * one dependency on EventAdmin; this manager directs all calls from the ChangeNotifiers
+ * to the 'real' EventAdmin.
+ */
+public class ChangeNotifierManager implements EventAdmin {
+
+ private volatile EventAdmin m_eventAdmin; /* Will be injected by dependency manager */
+
+ /**
+ * Creates and configures a ChangeNotifier for use with the given topics.
+ * @param privateTopicRoot The root of all private topics; see TopicRoot in the description of {@link ChangeNotifierImpl}.
+ * @param publicTopicRoot The root of all public topics; see TopicRoot in the description of {@link ChangeNotifierImpl}.
+ * @param entityRoot A class-specific root for the class which will use this ChangeNotifierImpl.
+ * @return The newly configured ChangeNotifier.
+ */
+ public ChangeNotifier getConfiguredNotifier(String privateTopicRoot, String publicTopicRoot, String entityRoot, String sessionID) {
+ return new ChangeNotifierImpl(this, privateTopicRoot, publicTopicRoot, entityRoot, sessionID);
+ }
+
+ public void postEvent(Event event) {
+ m_eventAdmin.postEvent(event);
+ }
+
+ public void sendEvent(Event event) {
+ m_eventAdmin.sendEvent(event);
+ }
+
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/DeploymentArtifactImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/DeploymentArtifactImpl.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/DeploymentArtifactImpl.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/DeploymentArtifactImpl.java Tue Apr 2 14:53:33 2013
@@ -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.apache.ace.client.repository.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.ace.client.repository.object.DeploymentArtifact;
+
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
+
+
+/**
+ * This class is a basic implementation of DeploymentArtifact, with additional facilities
+ * for serializing this artifacts with its directives.
+ */
+public class DeploymentArtifactImpl implements DeploymentArtifact {
+ private final static String XML_NODE = "deploymentArtifact";
+ private final static String XML_NODE_URL = "url";
+ private final static String XML_NODE_DIRECTIVES = "directives";
+ private final String m_url;
+ private final Map<String, String> m_directives = new HashMap<String, String>();
+
+ /**
+ * Creates a new DeploymentArtifactImpl.
+ * @param url The url to the new artifact, as a string; should not be null;
+ */
+ public DeploymentArtifactImpl(String url) {
+ if (url == null) {
+ throw new IllegalArgumentException("The url should not be null.");
+ }
+ m_url = url;
+ }
+
+ /**
+ * Creates a new DeploymentArtifactImpl by deserializing it from an XML stream.
+ * @param reader A stream reader for the XML representation of this object.
+ */
+ public DeploymentArtifactImpl(HierarchicalStreamReader reader) {
+ reader.moveDown();
+ m_url = reader.getValue();
+ reader.moveUp();
+
+ reader.moveDown();
+ while (reader.hasMoreChildren()) {
+ reader.moveDown();
+ m_directives.put(reader.getNodeName(), reader.getValue());
+ reader.moveUp();
+ }
+ reader.moveUp();
+
+ }
+
+ /**
+ * Writes this object to an XML stream.
+ */
+ public void marshal(HierarchicalStreamWriter writer) {
+ writer.startNode(XML_NODE);
+
+ writer.startNode(XML_NODE_URL);
+ writer.setValue(m_url);
+ writer.endNode(); // url node
+
+ writer.startNode(XML_NODE_DIRECTIVES);
+ for (Map.Entry<String, String> entry : m_directives.entrySet()) {
+ writer.startNode(entry.getKey());
+ assert (entry.getValue() != null);
+ writer.setValue(entry.getValue());
+ writer.endNode(); // this directive entry
+ }
+ writer.endNode(); // directives node
+
+ writer.endNode(); // deploymentartifact node
+ }
+
+ /**
+ * Adds a directive to this object.
+ */
+ void addDirective(String key, String value) {
+ if ((key == null) || (value == null)) {
+ throw new IllegalArgumentException("Neither the key nor the value should be null.");
+ }
+ m_directives.put(key, value);
+ }
+
+ public String getDirective(String key) {
+ return m_directives.get(key);
+ }
+
+ public String[] getKeys() {
+ return m_directives.keySet().toArray(new String[m_directives.size()]);
+ }
+
+ public String getUrl() {
+ return m_url;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if ((other == null) || !getClass().equals(other.getClass())) {
+ return false;
+ }
+
+ DeploymentArtifactImpl dai = (DeploymentArtifactImpl) other;
+
+ boolean result = true;
+
+ result &= getUrl().equals(dai.getUrl());
+
+ result &= (getKeys().length == dai.getKeys().length);
+
+ for (String key : getKeys()) {
+ result &= getDirective(key).equals(dai.getDirective(key));
+ }
+
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = getUrl().hashCode();
+
+ for (String key : getKeys()) {
+ result ^= getDirective(key).hashCode();
+ }
+
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder result = new StringBuilder(getUrl() + " [ ");
+ for (String key : getKeys()) {
+ result.append(key)
+ .append(": ")
+ .append(getDirective(key))
+ .append(" ");
+ }
+ result.append("]");
+
+ return result.toString();
+ }
+
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/DeploymentVersionObjectImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/DeploymentVersionObjectImpl.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/DeploymentVersionObjectImpl.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/DeploymentVersionObjectImpl.java Tue Apr 2 14:53:33 2013
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.repository.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ace.client.repository.object.DeploymentArtifact;
+import org.apache.ace.client.repository.object.DeploymentVersionObject;
+
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
+
+/**
+ * Implementation class for the DeploymentVersionObject. For 'what it does', see DeploymentVersionObject,
+ * for 'how it works', see RepositoryObjectImpl.
+ */
+public class DeploymentVersionObjectImpl extends RepositoryObjectImpl<DeploymentVersionObject> implements DeploymentVersionObject {
+ private final static String XML_NODE = "deploymentversion";
+ private final static String ARTIFACTS_XML_NODE = "artifacts";
+ private DeploymentArtifact[] m_deploymentArtifacts;
+
+ /**
+ * Creates a new <code>DeploymentVersionObjectImpl</code>.
+ * @param attributes A map of attributes; must include <code>KEY_TARGETID</code>, <code>KEY_VERSION</code>.
+ * @param deploymentArtifacts A (possibly empty) array of DeploymentArtifacts.
+ * @param notifier A change notifier to be used by this object.
+ */
+ DeploymentVersionObjectImpl(Map<String, String> attributes, ChangeNotifier notifier) {
+ super(checkAttributes(attributes, new String[] {KEY_TARGETID, KEY_VERSION}, new boolean[] {false, false}), notifier, XML_NODE);
+ }
+
+ DeploymentVersionObjectImpl(Map<String, String> attributes, Map<String, String> tags, ChangeNotifier notifier) {
+ super(checkAttributes(attributes, new String[] {KEY_TARGETID, KEY_VERSION}, new boolean[] {false, false}), tags, notifier, XML_NODE);
+ }
+
+ DeploymentVersionObjectImpl(HierarchicalStreamReader reader, ChangeNotifier notifier) {
+ super(reader, notifier, XML_NODE);
+ }
+
+ synchronized void setDeploymentArtifacts(DeploymentArtifact[] deploymentArtifacts) {
+ if (m_deploymentArtifacts != null) {
+ throw new IllegalStateException("Deployment artifacts are already set; this can only be done once.");
+ }
+ if (deploymentArtifacts == null) {
+ throw new IllegalArgumentException("The argument should not be null.");
+ }
+ else {
+ m_deploymentArtifacts = deploymentArtifacts;
+ }
+ }
+
+ @Override
+ protected void readCustom(HierarchicalStreamReader reader) {
+ List<DeploymentArtifact> result = new ArrayList<DeploymentArtifact>();
+ reader.moveDown();
+ while (reader.hasMoreChildren()) {
+ reader.moveDown();
+ DeploymentArtifactImpl deploymentArtifactImpl = new DeploymentArtifactImpl(reader);
+ result.add(deploymentArtifactImpl);
+ reader.moveUp();
+ }
+ setDeploymentArtifacts(result.toArray(new DeploymentArtifact[result.size()]));
+ reader.moveUp();
+ }
+
+ @Override
+ protected synchronized void writeCustom(HierarchicalStreamWriter writer) {
+ if (m_deploymentArtifacts == null) {
+ throw new IllegalStateException("This object is not fully initialized, so it cannot be serialized.");
+ }
+ writer.startNode(ARTIFACTS_XML_NODE);
+ for (DeploymentArtifact da : m_deploymentArtifacts) {
+ ((DeploymentArtifactImpl) da).marshal(writer);
+ }
+ writer.endNode();
+ }
+
+ private static String[] DEFINING_KEYS = new String[] {KEY_TARGETID, KEY_VERSION};
+ @Override
+ String[] getDefiningKeys() {
+ return DEFINING_KEYS;
+ }
+
+ public String getTargetID() {
+ return getAttribute(KEY_TARGETID);
+ }
+
+ public String getVersion() {
+ return getAttribute(KEY_VERSION);
+ }
+
+ public synchronized DeploymentArtifact[] getDeploymentArtifacts() {
+ if (m_deploymentArtifacts == null) {
+ throw new IllegalStateException("This object is not fully initialized yet.");
+ }
+ return m_deploymentArtifacts.clone();
+ }
+}
+
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/DeploymentVersionRepositoryImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/DeploymentVersionRepositoryImpl.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/DeploymentVersionRepositoryImpl.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/DeploymentVersionRepositoryImpl.java Tue Apr 2 14:53:33 2013
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.repository.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ace.client.repository.RepositoryUtil;
+import org.apache.ace.client.repository.object.DeploymentArtifact;
+import org.apache.ace.client.repository.object.DeploymentVersionObject;
+import org.apache.ace.client.repository.repository.DeploymentVersionRepository;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.Version;
+
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+
+/**
+ * Implementation class for the TargetRepository. For 'what it does', see TargetRepository,
+ * for 'how it works', see ObjectRepositoryImpl.
+ * TODO: For now, this class reuses the functionality of ObjectRepositoryImpl. In the future, it
+ * might be useful to create a custom implementation for performance reasons.
+ */
+public class DeploymentVersionRepositoryImpl extends ObjectRepositoryImpl<DeploymentVersionObjectImpl, DeploymentVersionObject> implements DeploymentVersionRepository {
+ private final static String XML_NODE = "deploymentversions";
+
+ public DeploymentVersionRepositoryImpl(ChangeNotifier notifier) {
+ super(notifier, XML_NODE);
+ }
+
+ /*
+ * The mechanism below allows us to insert the artifacts that are passed to create
+ * into the newInhabitant, while still using the nice handling of ObjectRepositoryImpl.
+ */
+ private DeploymentArtifact[] m_tempDeploymentArtifacts;
+ private final Object m_creationLock = new Object();
+
+ @Override
+ DeploymentVersionObjectImpl createNewInhabitant(Map<String, String> attributes) {
+ synchronized (m_creationLock) {
+ DeploymentVersionObjectImpl result = new DeploymentVersionObjectImpl(attributes, this);
+ result.setDeploymentArtifacts(m_tempDeploymentArtifacts);
+ m_tempDeploymentArtifacts = null;
+ return result;
+ }
+ }
+
+ @Override
+ DeploymentVersionObjectImpl createNewInhabitant(Map<String, String> attributes, Map<String, String> tags) {
+ synchronized (m_creationLock) {
+ DeploymentVersionObjectImpl result = new DeploymentVersionObjectImpl(attributes, tags, this);
+ result.setDeploymentArtifacts(m_tempDeploymentArtifacts);
+ m_tempDeploymentArtifacts = null;
+ return result;
+ }
+ }
+
+ @Override
+ DeploymentVersionObjectImpl createNewInhabitant(HierarchicalStreamReader reader) {
+ return new DeploymentVersionObjectImpl(reader, this);
+ }
+
+ public DeploymentVersionObject create(Map<String, String> attributes, Map<String, String> tags, DeploymentArtifact[] artifacts) {
+ synchronized (m_creationLock) {
+ m_tempDeploymentArtifacts = artifacts;
+ return super.create(attributes, tags);
+ }
+ }
+
+ private Comparator<DeploymentVersionObject> versionComparator = new Comparator<DeploymentVersionObject>() {
+ public int compare(DeploymentVersionObject o1, DeploymentVersionObject o2) {
+ return Version.parseVersion(o1.getVersion()).compareTo(Version.parseVersion(o2.getVersion()));
+ }
+ };
+
+ public List<DeploymentVersionObject> getDeploymentVersions(String targetID) {
+ List<DeploymentVersionObject> result = null;
+ try {
+ result = get(createFilter("(" + DeploymentVersionObject.KEY_TARGETID + "=" + RepositoryUtil.escapeFilterValue(targetID) + ")"));
+ Collections.sort(result, versionComparator);
+ }
+ catch (InvalidSyntaxException e) {
+ // Too bad, probably an illegal targetID.
+ result = new ArrayList<DeploymentVersionObject>();
+ }
+ return result;
+ }
+
+ public DeploymentVersionObject getMostRecentDeploymentVersion(String targetID) {
+ List<DeploymentVersionObject> versions = getDeploymentVersions(targetID);
+ DeploymentVersionObject result = null;
+ if ((versions != null) && (versions.size() > 0)) {
+ result = versions.get(versions.size() - 1);
+ }
+ return result;
+ }
+
+ public DeploymentArtifact createDeploymentArtifact(String url, Map<String, String> directives) {
+ DeploymentArtifactImpl result = new DeploymentArtifactImpl(url);
+ for (Map.Entry<String, String> entry : directives.entrySet()) {
+ result.addDirective(entry.getKey(), entry.getValue());
+ }
+ return result;
+ }
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/Distribution2TargetAssociationImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/Distribution2TargetAssociationImpl.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/Distribution2TargetAssociationImpl.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/Distribution2TargetAssociationImpl.java Tue Apr 2 14:53:33 2013
@@ -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.apache.ace.client.repository.impl;
+
+import java.util.Map;
+
+import org.apache.ace.client.repository.object.TargetObject;
+import org.apache.ace.client.repository.object.Distribution2TargetAssociation;
+import org.apache.ace.client.repository.object.DistributionObject;
+import org.osgi.framework.InvalidSyntaxException;
+
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+
+/**
+ * Implementation class for the Distribution2TargetAssociation. For 'what it does', see Distribution2TargetAssociation,
+ * for 'how it works', see AssociationImpl.
+ */
+public class Distribution2TargetAssociationImpl extends AssociationImpl<DistributionObject, TargetObject, Distribution2TargetAssociation> implements Distribution2TargetAssociation {
+ private final static String XML_NODE = "distribution2target";
+
+ public Distribution2TargetAssociationImpl(Map<String, String> attributes, ChangeNotifier notifier, DistributionRepositoryImpl distributionRepository, TargetRepositoryImpl targetRepository) throws InvalidSyntaxException {
+ super(attributes, notifier, DistributionObject.class, TargetObject.class, distributionRepository, targetRepository, XML_NODE);
+ }
+ public Distribution2TargetAssociationImpl(Map<String, String> attributes, Map<String, String> tags, ChangeNotifier notifier, DistributionRepositoryImpl distributionRepository, TargetRepositoryImpl targetRepository) throws InvalidSyntaxException {
+ super(attributes, tags, notifier, DistributionObject.class, TargetObject.class, distributionRepository, targetRepository, XML_NODE);
+ }
+ public Distribution2TargetAssociationImpl(HierarchicalStreamReader reader, ChangeNotifier notifier, DistributionRepositoryImpl distributionRepository, TargetRepositoryImpl targetRepository) throws InvalidSyntaxException {
+ super(reader, notifier, DistributionObject.class, TargetObject.class, null, null, distributionRepository, targetRepository, XML_NODE);
+ }
+}