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 [6/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/repository/ArtifactRepository.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/ArtifactRepository.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/ArtifactRepository.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/ArtifactRepository.java Tue Apr 2 14:53:33 2013
@@ -0,0 +1,109 @@
+/*
+ * 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.repository;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+
+import org.apache.ace.client.repository.ObjectRepository;
+import org.apache.ace.client.repository.object.ArtifactObject;
+import org.apache.ace.client.repository.object.TargetObject;
+
+/**
+ * Interface to a ArtifactRepository. The functionality is defined by the generic AssociationRepository.
+ */
+public interface ArtifactRepository extends ObjectRepository<ArtifactObject> {
+ /**
+ * Gets a list of all ArtifactObject's which are resource processing bundles.
+ */
+ public List<ArtifactObject> getResourceProcessors();
+
+ /**
+ * Tries to import an artifact into storage, while extracting necessary metadata.
+ * @param artifact a URL pointing to the 'physical' artifact.
+ * @param upload Indicates whether this artifact should be uploaded to our own OBR.
+ * @return An <code>ArtifactObject</code> representing the passed in artifact, if
+ * (a) the artifact is recognized, (b) there is storage available and (c) there is
+ * a resource processor available for this type of artifact.
+ * @throws IllegalArgumentException when the <code>artifact</code> cannot be processed.
+ * @throws IOException when there is a problem transferring the <code>artifact</code> to storage.
+ */
+ public ArtifactObject importArtifact(URL artifact, boolean upload) throws IllegalArgumentException, IOException;
+
+ /**
+ * Checks whether an artifact is 'usable', that is, there is a resource processor available for it,
+ * if necessary.
+ * @param artifact A URL pointing to an artifact.
+ * @return <code>true</code> if the artifact is recognized, and a processor for it is available. <code>false</code>
+ * otherwise, including when the artifact cannot be reached.
+ */
+ public boolean recognizeArtifact(URL artifact);
+
+ /**
+ * Tries to import an artifact into storage, while extracting necessary metadata.
+ * @param artifact a URL pointing to the 'physical' artifact.
+ * @param mimetype a String giving this object's mimetype.
+ * @param upload Indicates whether this artifact should be uploaded to our own OBR.
+ * @return An <code>ArtifactObject</code> representing the passed in artifact, if
+ * (a) there is storage available and (b) there is a resource processor
+ * available for this type of artifact.
+ * @throws IllegalArgumentException when the <code>artifact</code> cannot be processed.
+ * @throws IOException when there is a problem transferring the <code>artifact</code> to storage.
+ */
+ public ArtifactObject importArtifact(URL artifact, String mimetype, boolean upload) throws IllegalArgumentException, IOException;
+
+ /**
+ * Tries to locate a preprocessor for the passed artifact, an processes it. If no processing
+ * needs to be done, the original artifact's URL will be returned.
+ * @param artifact An artifact
+ * @param props A tree of properties objects, to be used for replacement.
+ * @param targetID The targetID of the target for which this artifact is being processed.
+ * @param version The deployment version for which this artifact is being processed.
+ * @return A URL to a new, processed artifact, or to the original one, in case nothing needed to be processed.
+ * @throws IOException Thrown if reading the original artifact goes wrong, or storing the processed one.
+ */
+ public String preprocessArtifact(ArtifactObject artifact, TargetObject target, String targetID, String version) throws IOException ;
+
+ /**
+ * Indicates whether the template should be processed again, given the properties, and the version to which it
+ * should be compared.
+ * @param url A string representing a URL to the original artifact.
+ * @param props A PropertyResolver which can be used to fill in 'holes' in the template.
+ * @param targetID The targetID of the target for which this artifact is being processed.
+ * @param version The deployment version for which this artifact is being processed.
+ * @param lastVersion The deployment version to which the current one should be compared.
+ * @param newVersion The new, potential version.
+ * @param obrBase A base OBR to upload the new artifact to.
+ * @return Whether or not a new version has to be created.
+ * @throws IOException
+ */
+ public boolean needsNewVersion(ArtifactObject artifact, TargetObject target, String targetID, String fromVersion);
+
+ /**
+ * Sets the OBR that this artifact repository should use to upload artifacts to.
+ */
+ public void setObrBase(URL obrBase);
+
+ /**
+ * Gets the OBR that this artifact repository should use to upload artifacts to.
+ * Note that this method may return <code>null</code> if no base was set earlier.
+ */
+ public URL getObrBase();
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/DeploymentVersionRepository.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/DeploymentVersionRepository.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/DeploymentVersionRepository.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/DeploymentVersionRepository.java Tue Apr 2 14:53:33 2013
@@ -0,0 +1,46 @@
+package org.apache.ace.client.repository.repository;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ace.client.repository.ObjectRepository;
+import org.apache.ace.client.repository.object.DeploymentArtifact;
+import org.apache.ace.client.repository.object.DeploymentVersionObject;
+
+
+/**
+ * Interface to a DeploymentVersionRepository. The functionality is defined by the generic ObjectRepository.
+ */
+public interface DeploymentVersionRepository extends ObjectRepository<DeploymentVersionObject> {
+ /**
+ * Creates a new inhabitant based on the given attributes and bundle URLs. The object
+ * will be stored in this repository's store, and will be returned.
+ * @throws IllegalArgumentException Will be thrown when the attributes cannot be accepted.
+ */
+ public DeploymentVersionObject create(Map<String, String> attributes, Map<String, String> tags, DeploymentArtifact[] artifacts);
+
+ /**
+ * Gets all available deployment versions for this target. If none can be
+ * found, an empty list will be returned.
+ * @param targetID The target to be used.
+ * @return A list of <code>DeploymentVersionObject</code>s which are related to
+ * this target, sorted lexically by version.
+ */
+ public List<DeploymentVersionObject> getDeploymentVersions(String targetID);
+
+ /**
+ * Get the most recent known deployment version for a given target.
+ * @param targetID The target to be used.
+ * @return A <code>DeploymentVersionObject</code> which is the most recent one to be deployed
+ * to the target. If none can be found, <code>null</code> will be returned.
+ */
+ public DeploymentVersionObject getMostRecentDeploymentVersion(String targetID);
+
+ /**
+ * Creates a DeploymentArtifact object.
+ * @param url The url to be used in this object.
+ * @param directives A map of directives to be packed into the object.
+ * @return The newly created deployment artifact object.
+ */
+ public DeploymentArtifact createDeploymentArtifact(String url, Map<String, String> directives);
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/Distribution2TargetAssociationRepository.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/Distribution2TargetAssociationRepository.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/Distribution2TargetAssociationRepository.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/Distribution2TargetAssociationRepository.java Tue Apr 2 14:53:33 2013
@@ -0,0 +1,38 @@
+/*
+ * 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.repository;
+
+import org.apache.ace.client.repository.AssociationRepository;
+import org.apache.ace.client.repository.object.TargetObject;
+import org.apache.ace.client.repository.object.Distribution2TargetAssociation;
+import org.apache.ace.client.repository.object.DistributionObject;
+
+/**
+ * Interface to a Distribution2TargetAssociationRepository. The functionality is defined by the generic AssociationRepository.
+ */
+public interface Distribution2TargetAssociationRepository extends AssociationRepository<DistributionObject, TargetObject, Distribution2TargetAssociation> {
+ /**
+ * Creates an assocation from a given distribution to multiple targets, which correspond to the given
+ * filter string. For parameters to use in the filter, see <code>TargetObject</code>'s <code>KEY_</code> constants.
+ * @param distribution A distribution object for the left side of this association.
+ * @param targetFilter An LDAP-filter for the targets to use.
+ * @return The newly created association.
+ */
+ public Distribution2TargetAssociation createDistribution2TargetFilter(DistributionObject distribution, String targetFilter);
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/DistributionRepository.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/DistributionRepository.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/DistributionRepository.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/DistributionRepository.java Tue Apr 2 14:53:33 2013
@@ -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.apache.ace.client.repository.repository;
+
+import org.apache.ace.client.repository.ObjectRepository;
+import org.apache.ace.client.repository.object.DistributionObject;
+
+/**
+ * Interface to a DistributionRepository. The functionality is defined by the generic AssociationRepository.
+ */
+public interface DistributionRepository extends ObjectRepository<DistributionObject> {
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/Feature2DistributionAssociationRepository.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/Feature2DistributionAssociationRepository.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/Feature2DistributionAssociationRepository.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/Feature2DistributionAssociationRepository.java Tue Apr 2 14:53:33 2013
@@ -0,0 +1,30 @@
+/*
+ * 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.repository;
+
+import org.apache.ace.client.repository.AssociationRepository;
+import org.apache.ace.client.repository.object.Feature2DistributionAssociation;
+import org.apache.ace.client.repository.object.FeatureObject;
+import org.apache.ace.client.repository.object.DistributionObject;
+
+/**
+ * Interface to a Feature2DistributionAssociationRepository. The functionality is defined by the generic AssociationRepository.
+ */
+public interface Feature2DistributionAssociationRepository extends AssociationRepository<FeatureObject, DistributionObject, Feature2DistributionAssociation> {
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/FeatureRepository.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/FeatureRepository.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/FeatureRepository.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/FeatureRepository.java Tue Apr 2 14:53:33 2013
@@ -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.apache.ace.client.repository.repository;
+
+import org.apache.ace.client.repository.ObjectRepository;
+import org.apache.ace.client.repository.object.FeatureObject;
+
+/**
+ * Interface to a FeatureRepository. The functionality is defined by the generic AssociationRepository.
+ */
+public interface FeatureRepository extends ObjectRepository<FeatureObject> {
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/TargetRepository.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/TargetRepository.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/TargetRepository.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/TargetRepository.java Tue Apr 2 14:53:33 2013
@@ -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.apache.ace.client.repository.repository;
+
+import org.apache.ace.client.repository.ObjectRepository;
+import org.apache.ace.client.repository.object.TargetObject;
+
+/**
+ * Interface to a GatewayRepository. The functionality is defined by the generic AssociationRepository.
+ */
+public interface TargetRepository extends ObjectRepository<TargetObject>{
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/packageinfo
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/packageinfo?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/packageinfo (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/packageinfo Tue Apr 2 14:53:33 2013
@@ -0,0 +1 @@
+version 1.0
\ No newline at end of file
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/StatefulTargetObject.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/StatefulTargetObject.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/StatefulTargetObject.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/StatefulTargetObject.java Tue Apr 2 14:53:33 2013
@@ -0,0 +1,207 @@
+/*
+ * 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.stateful;
+
+import java.util.List;
+
+import org.apache.ace.client.repository.RepositoryObject;
+import org.apache.ace.client.repository.object.ArtifactObject;
+import org.apache.ace.client.repository.object.DeploymentArtifact;
+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.apache.ace.log.LogEvent;
+
+/**
+ * Represents the information that a <code>TargetObject</code>
+ * has, plus added functionality for gathering information from a deployment repository and,
+ * optionally, from an AuditLog.
+ */
+public interface StatefulTargetObject extends RepositoryObject {
+
+ public static final String TOPIC_ADDED = StatefulTargetObject.class.getName().replace('.', '/') + "/ADDED";
+ public static final String TOPIC_REMOVED = StatefulTargetObject.class.getName().replace('.', '/') + "/REMOVED";
+ public static final String TOPIC_CHANGED = StatefulTargetObject.class.getName().replace('.', '/') + "/CHANGED";
+ public static final String TOPIC_STATUS_CHANGED = StatefulTargetObject.class.getName().replace('.', '/') + "/STATUS_CHANGED";
+ /** Indicates a change to the audit events for the StatefulTargetObject in "entity".*/
+ public static final String TOPIC_AUDITEVENTS_CHANGED = StatefulTargetObject.class.getName().replace('.', '/') + "/AUDITEVENTS_CHANGED";
+ /** Key used in the event with topic <code>TOPIC_AUDITEVENTS_CHANGED</code>. Contains a List<LogDescriptor> containing all
+ * events we have not seen yet. NOTE: The first auditevent "change" causing the <code>StatefulTargetObject</code> to
+ * be instantiated will trigger a <code>TOPIC_AUDITEVENTS_CHANGED</code> event *before* a <code>TOPIC_ADDED</code> event. */
+ public static final String KEY_AUDITEVENTS = "auditevents";
+ public static final String TOPIC_ALL = StatefulTargetObject.class.getName().replace('.', '/') + "/*";
+
+ public final static String KEY_ID = TargetObject.KEY_ID;
+ public final static String KEY_REGISTRATION_STATE = "KEY_REGISTRATION_STATE";
+ public final static String KEY_STORE_STATE = "KEY_STORE_STATE";
+ public final static String KEY_PROVISIONING_STATE = "KEY_PROVISIONING_STATE";
+ public final static String KEY_LAST_INSTALL_VERSION = "KEY_LAST_INSTALL_VERSION";
+ public final static String KEY_LAST_INSTALL_SUCCESS = "KEY_LAST_INSTALL_SUCCESS";
+ public final static String KEY_ACKNOWLEDGED_INSTALL_VERSION = "KEY_ACKNOWLEDGED_INSTALL_VERSION";
+ public final static String[] KEYS_ALL = new String[] {KEY_ID, KEY_REGISTRATION_STATE, KEY_STORE_STATE, KEY_PROVISIONING_STATE, KEY_LAST_INSTALL_VERSION, KEY_LAST_INSTALL_SUCCESS, KEY_ACKNOWLEDGED_INSTALL_VERSION};
+
+ /**
+ * Represents a current deployment package version which cannot be found, i.e.,
+ * either there is no information about deployment packages in the AuditLog,
+ * or no AuditLog is available.
+ */
+ public final static String UNKNOWN_VERSION = "(unknown)";
+
+ /**
+ * Gets the current registration status of the target.
+ */
+ public RegistrationState getRegistrationState();
+
+ /**
+ * Gets the current store status of the target.
+ */
+ public StoreState getStoreState();
+
+ /**
+ * Gets the current provisioning status of the target.
+ */
+ public ProvisioningState getProvisioningState();
+
+ /**
+ * Gets the most recent deployment package version on the target, according
+ * to the deployment repository. If no version can be determined,
+ * <code>UNKNOWN_VERSION</code> will be returned.
+ */
+ public String getCurrentVersion();
+
+ /**
+ * Gets the list of AuditLog Events for this target. If no auditlog events
+ * can be found, and empty list will be returned. The events are ordered ascending by timestamp.
+ */
+ public List<LogEvent> getAuditEvents();
+
+ /**
+ * Registers this target, which for now only exists in the AuditLog, into the
+ * <code>TargetRepository</code>.
+ * @throws IllegalStateException when the precondition is not met, i.e., the
+ * target is not known only in the AuditLog, but also in the <code>TargetRepository</code>.
+ */
+ public void register() throws IllegalStateException;
+
+ /**
+ * Indicates whether this <code>StatefulTargetObject</code> is backed by a <code>TargetObject</code>.
+ * @return whether this <code>StatefulTargetObject</code> is backed by a <code>TargetObject</code>.
+ */
+ public boolean isRegistered();
+
+ /**
+ * Approves all differences between what is currently in the shop and target operator
+ * repository, and the deployment repository. This will generate a new version in the
+ * deployment repository.
+ * @return The number of the new version.
+ * @throws IllegalStateException when it is currently not possible to create a deployment version.
+ */
+ public String approve();
+
+ /**
+ * Indicates whether an <code>approve()</code> is necessary, i.e., there is a difference between
+ * the set of artifacts for this target according to the shop, and according to the deployment
+ * repository.
+ * @return <code>true</code> if there is a difference between the shop and deployment repository;
+ * <code>false</code> otherwise.
+ */
+ public boolean needsApprove();
+
+ /**
+ * Returns the auto-approval flag for this target.
+ * @return <code>true</code> if auto approve has been set;
+ * <code>false</code> otherwise.
+ */
+ public boolean getAutoApprove();
+
+ /**
+ * Set the auto approve value for this target, the property is stored within the target
+ * @param approve <code>true</code> to enable auto approve;
+ * <code>false</code> otherwise.
+ */
+ public void setAutoApprove(boolean approve);
+
+ /**
+ * Gets the list of artifact objects that should be on the target, according to the shop.
+ * @return the list of artifact objects that should be on the target, according to the shop, can only be <code>null</code> in case something went wrong gathering artifacts.
+ */
+ public ArtifactObject[] getArtifactsFromShop();
+
+ /**
+ * Gets the list of deployment artifacts that should be on the target, according to the deployment repository.
+ * @return the list of artifact objects that should be on the target, according to the deployment repository.
+ */
+ public DeploymentArtifact[] getArtifactsFromDeployment();
+
+ /**
+ * Returns the latest available installed version in the auditlog.
+ * @return The latest version statement from the auditlog for an install if
+ * one is available; otherwise, an empty string.
+ */
+ public String getLastInstallVersion();
+
+ /**
+ * Returns whether the last install on the target was successful.
+ * @return <code>true</code> if there information about a last install and
+ * that was successful, <code>false</code> otherwise.
+ */
+ public boolean getLastInstallSuccess();
+
+ /**
+ * Signals to the object that the outcome of a given install on the target
+ * is 'seen', and that the <code>ProvisioningState</code> can now return to <code>Idle</code>.
+ * @param version A string representing a version.
+ */
+ public void acknowledgeInstallVersion(String version);
+
+ /**
+ * Gets the underlying <code>TargetObject</code> of this <code>StatefulTargetObject</code>.
+ * @return The <code>TargetObject</code> linked to this <code>StatefulTargetObject</code>; if none
+ * is available, an <code>IllegalStateException</code> will be thrown.
+ */
+ public TargetObject getTargetObject();
+
+ /**
+ * Returns all <code>DistributionObject</code>s this object is associated with. If there
+ * are none, an empty list will be returned.
+ */
+ public List<DistributionObject> getDistributions();
+
+ /**
+ * Returns all associations this target has with a given distribution.
+ */
+ public List<Distribution2TargetAssociation> getAssociationsWith(DistributionObject distribution);
+
+ /**
+ * Gets the ID of this TargetObject.
+ */
+ public String getID();
+
+ public enum RegistrationState {
+ Unregistered, Registered;
+ }
+
+ public enum StoreState {
+ New, Unapproved, Approved;
+ }
+
+ public enum ProvisioningState {
+ Idle, InProgress, OK, Failed;
+ }
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/StatefulTargetRepository.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/StatefulTargetRepository.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/StatefulTargetRepository.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/StatefulTargetRepository.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.stateful;
+
+import java.util.Map;
+
+import org.apache.ace.client.repository.ObjectRepository;
+
+/**
+ * Represents a repository of <ode>StatefulTargetObject</code>'s.
+ */
+public interface StatefulTargetRepository extends ObjectRepository<StatefulTargetObject> {
+
+ /**
+ * Registers a target with given attributes. This will result in the creation
+ * of a <code>TargetObject</code> in the <code>TargetRepository</code>, and
+ * the creation of a <code>StatefulTargetObject</code>, which will also be
+ * returned.
+ * @param attributes The attributes to create the <code>TargetObject</code> with.
+ * @return The newly registered target object.
+ */
+ public StatefulTargetObject preregister(Map<String, String> attributes, Map<String, String> tags);
+
+ /**
+ * Unregisters a target, removing it from the <code>TargetRepository</code>. Note
+ * that a <code>StatefulTargetObject</code> might stay around if it is backed
+ * by audit log entries. If the given ID is not that of an existing <code>TargetObject</code>,
+ * an <code>IllegalArgumentException</code> will be thrown.
+ * @param targetID A string representing a target ID.
+ */
+ public void unregister(String targetID);
+
+ /**
+ * Explicitly instruct the <code>StatefulTargetRepository</code> to update
+ * its contents; for instance, after syncing the audit log.
+ */
+ public void refresh();
+
+}
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/LogEventComparator.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/LogEventComparator.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/LogEventComparator.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/LogEventComparator.java Tue Apr 2 14:53:33 2013
@@ -0,0 +1,44 @@
+/*
+ * 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.stateful.impl;
+
+import java.util.Comparator;
+
+import org.apache.ace.log.LogEvent;
+
+public final class LogEventComparator implements Comparator<LogEvent> {
+ public int compare(LogEvent left, LogEvent right) {
+ if (left.getLogID() == right.getLogID()) {
+ return sgn(left.getTime() - right.getTime());
+ }
+ else {
+ return sgn(left.getLogID() - right.getLogID());
+ }
+ }
+
+ public int sgn(long number) {
+ if (number < 0) {
+ return -1;
+ }
+ else if (number > 0) {
+ return 1;
+ }
+ return 0;
+ }
+}
\ No newline at end of file
Added: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/StatefulTargetObjectImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/StatefulTargetObjectImpl.java?rev=1463576&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/StatefulTargetObjectImpl.java (added)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/stateful/impl/StatefulTargetObjectImpl.java Tue Apr 2 14:53:33 2013
@@ -0,0 +1,717 @@
+/*
+ * 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.stateful.impl;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Properties;
+
+import org.apache.ace.client.repository.Associatable;
+import org.apache.ace.client.repository.Association;
+import org.apache.ace.client.repository.object.ArtifactObject;
+import org.apache.ace.client.repository.object.DeploymentArtifact;
+import org.apache.ace.client.repository.object.DeploymentVersionObject;
+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.apache.ace.client.repository.stateful.StatefulTargetObject;
+import org.apache.ace.log.AuditEvent;
+import org.apache.ace.log.LogDescriptor;
+import org.apache.ace.log.LogEvent;
+
+/**
+ * A <code>StatefulTargetObjectImpl</code> uses the interface of a <code>StatefulTargetObject</code>,
+ * but delegates most of its calls to either an embedded <code>TargetObject</code>, or to its
+ * parent <code>StatefulTargetRepository</code>. Once created, it will handle its own lifecycle
+ * and remove itself once is existence is no longer necessary.
+ */
+public class StatefulTargetObjectImpl implements StatefulTargetObject {
+ private final StatefulTargetRepositoryImpl m_repository;
+ private final Object m_lock = new Object();
+ private TargetObject m_targetObject;
+ private List<LogDescriptor> m_processedAuditEvents = new ArrayList<LogDescriptor>();
+ private Map<String, String> m_attributes = new HashMap<String, String>();
+ /** This boolean is used to suppress STATUS_CHANGED events during the creation of the object.*/
+ private boolean m_inConstructor = true;
+
+ /**
+ * Creates a new <code>StatefulTargetObjectImpl</code>. After creation, it will have the
+ * most recent data available, and has verified its own reasons for existence.
+ * @param repository The parent repository of this object.
+ * @param targetID A string representing a target ID.
+ */
+ StatefulTargetObjectImpl(StatefulTargetRepositoryImpl repository, String targetID) {
+ m_repository = repository;
+ addStatusAttribute(KEY_ID, targetID);
+ updateTargetObject(false);
+ updateAuditEvents(false);
+ updateDeploymentVersions(null);
+ verifyExistence();
+ m_inConstructor = false;
+ }
+
+ public String approve() throws IllegalStateException {
+ try {
+ String version = m_repository.approve(getID());
+ setStoreState(StoreState.Approved);
+ return version;
+ }
+ catch (IOException e) {
+ throw new IllegalStateException("Problem generating new deployment version: " + e.getMessage(), e);
+ }
+ }
+
+ public List<LogEvent> getAuditEvents() {
+ return m_repository.getAuditEvents(getID());
+ }
+
+ public String getCurrentVersion() {
+ DeploymentVersionObject version = m_repository.getMostRecentDeploymentVersion(getID());
+ if (version == null) {
+ return StatefulTargetObject.UNKNOWN_VERSION;
+ }
+ else {
+ return version.getVersion();
+ }
+ }
+
+ public void register() throws IllegalStateException {
+ m_repository.register(getID());
+ }
+
+ public boolean isRegistered() {
+ synchronized(m_lock) {
+ return (m_targetObject != null);
+ }
+ }
+
+ public TargetObject getTargetObject() {
+ synchronized(m_lock) {
+ ensureTargetPresent();
+ return m_targetObject;
+ }
+ }
+
+ public DeploymentArtifact[] getArtifactsFromDeployment() {
+ synchronized(m_lock) {
+ DeploymentVersionObject mostRecentDeploymentVersion = m_repository.getMostRecentDeploymentVersion(getID());
+ if (mostRecentDeploymentVersion != null) {
+ return mostRecentDeploymentVersion.getDeploymentArtifacts();
+ }
+ return new DeploymentArtifact[0];
+ }
+ }
+
+ public ArtifactObject[] getArtifactsFromShop() {
+ return m_repository.getNecessaryArtifacts(getID());
+ }
+
+ public boolean getLastInstallSuccess() {
+ synchronized(m_lock) {
+ return Boolean.parseBoolean(getStatusAttribute(KEY_LAST_INSTALL_SUCCESS));
+ }
+ }
+
+ public String getLastInstallVersion() {
+ synchronized(m_lock) {
+ return getStatusAttribute(KEY_LAST_INSTALL_VERSION);
+ }
+ }
+
+ public void acknowledgeInstallVersion(String version) {
+ synchronized(m_lock) {
+ addStatusAttribute(KEY_ACKNOWLEDGED_INSTALL_VERSION, version);
+ if (version.equals(getStatusAttribute(KEY_LAST_INSTALL_VERSION))) {
+ setProvisioningState(ProvisioningState.Idle);
+ }
+ }
+ }
+
+ public boolean needsApprove() {
+ return getStoreState() == StoreState.Unapproved;
+ }
+
+ public ProvisioningState getProvisioningState() {
+ return ProvisioningState.valueOf(getStatusAttribute(KEY_PROVISIONING_STATE));
+ }
+
+ public RegistrationState getRegistrationState() {
+ return RegistrationState.valueOf(getStatusAttribute(KEY_REGISTRATION_STATE));
+ }
+
+ public StoreState getStoreState() {
+ String statusAttribute = getStatusAttribute(KEY_STORE_STATE);
+ if (statusAttribute != null) {
+ return StoreState.valueOf(statusAttribute);
+ }
+ return StoreState.New;
+ }
+
+ /**
+ * Signals this object that there has been a change to the <code>TargetObject</code> it represents.
+ * @param needsVerify States whether this update should make the object check for its
+ * reasons for existence.
+ */
+ void updateTargetObject(boolean needsVerify) {
+ synchronized(m_lock) {
+ m_targetObject = m_repository.getTargetObject(getID());
+ determineRegistrationState();
+ if (needsVerify) {
+ verifyExistence();
+ }
+ }
+ }
+
+ /**
+ * Signals this object that there has been a change to the auditlog which may interest
+ * this object.
+ * @param needsVerify States whether this update should make the object check for its
+ * reasons for existence.
+ */
+ void updateAuditEvents(boolean needsVerify) {
+ synchronized(m_lock) {
+ determineProvisioningState();
+ if (needsVerify) {
+ verifyExistence();
+ }
+ }
+ }
+
+ /**
+ * Signals this object that a new deployment version has been created in relation
+ * to the targetID this object manages.
+ */
+ void updateDeploymentVersions(DeploymentVersionObject deploymentVersionObject) {
+ synchronized(m_lock) {
+ determineProvisioningState();
+ determineStoreState(deploymentVersionObject);
+ }
+ }
+
+ /**
+ * Based on the information about a <code>TargetObject</code>, the
+ * <code>AuditEvent</code>s available, and the deployment information that
+ * the parent repository can give, determines the status of this target.
+ */
+ void determineStatus() {
+ determineRegistrationState();
+ determineProvisioningState();
+ determineStoreState(null);
+ verifyExistence();
+ }
+
+ private void determineRegistrationState() {
+ synchronized(m_lock) {
+ if (!isRegistered()) {
+ setRegistrationState(RegistrationState.Unregistered);
+ }
+ else {
+ setRegistrationState(RegistrationState.Registered);
+ }
+ }
+ }
+
+ private void determineStoreState(DeploymentVersionObject deploymentVersionObject) {
+ synchronized(m_lock) {
+ List<String> fromShop = new ArrayList<String>();
+ ArtifactObject[] artifactsFromShop = m_repository.getNecessaryArtifacts(getID());
+ DeploymentVersionObject mostRecentVersion;
+ if (deploymentVersionObject == null) {
+ mostRecentVersion = m_repository.getMostRecentDeploymentVersion(getID());
+ }
+ else {
+ mostRecentVersion = deploymentVersionObject;
+ }
+ if (artifactsFromShop == null) {
+ if (mostRecentVersion == null) {
+ setStoreState(StoreState.New);
+ }
+ else {
+ setStoreState(StoreState.Unapproved);
+ }
+ return;
+ }
+
+ for (ArtifactObject ao : artifactsFromShop) {
+ fromShop.add(ao.getURL());
+ }
+
+ List<String> fromDeployment = new ArrayList<String>();
+ for (DeploymentArtifact da : getArtifactsFromDeployment()) {
+ fromDeployment.add(da.getDirective(DeploymentArtifact.DIRECTIVE_KEY_BASEURL));
+ }
+
+ if ((mostRecentVersion == null) && fromShop.isEmpty()) {
+ setStoreState(StoreState.New);
+ }
+ else if (fromShop.containsAll(fromDeployment) && fromDeployment.containsAll(fromShop)) {
+ // great, we have the same artifacts. But... do they need to be reprocessed?
+ for (ArtifactObject ao : artifactsFromShop) {
+ if (m_repository.needsNewVersion(ao, getID(), mostRecentVersion.getVersion())) {
+ setStoreState(StoreState.Unapproved);
+ return;
+ }
+ }
+ setStoreState(StoreState.Approved);
+ }
+ else {
+ setStoreState(StoreState.Unapproved);
+ }
+ }
+ }
+
+ private void determineProvisioningState() {
+ /*
+ * This method gets all audit events it has not yet seen, and goes through them, backward
+ * in time, to find either and INSTALL or a COMPLETE event. A INSTALL event gives us a version,
+ * and tells us we're in InProgress. A COMPLETE tells gives us a version, and a success. The success
+ * will be stored, and also sets the state to OK or Failed, unless the version we found has already been
+ * acknowledged, the the state is set to Idle. Also, if there is no information whatsoever, we assume Idle.
+ */
+ synchronized(m_lock) {
+ List<LogDescriptor> allDescriptors = m_repository.getAllDescriptors(getID());
+ List<LogDescriptor> newDescriptors = m_repository.diffLogDescriptorLists(allDescriptors, m_processedAuditEvents);
+
+ List<LogEvent> newEvents = m_repository.getAuditEvents(newDescriptors);
+ for (int position = newEvents.size() - 1; position >= 0; position--) {
+ LogEvent event = newEvents.get(position);
+
+ // TODO we need to check here if the deployment package is actually the right one
+
+ String currentVersion = (String) event.getProperties().get(AuditEvent.KEY_VERSION);
+ if (event.getType() == AuditEvent.DEPLOYMENTCONTROL_INSTALL) {
+ addStatusAttribute(KEY_LAST_INSTALL_VERSION, currentVersion);
+ setProvisioningState(ProvisioningState.InProgress);
+ sendNewAuditlog(newDescriptors);
+ m_processedAuditEvents = allDescriptors;
+ return;
+ }
+ else if (event.getType() == AuditEvent.DEPLOYMENTADMIN_COMPLETE) {
+ addStatusAttribute(KEY_LAST_INSTALL_VERSION, currentVersion);
+ if ((currentVersion != null) && currentVersion.equals(getStatusAttribute(KEY_ACKNOWLEDGED_INSTALL_VERSION))) {
+ setProvisioningState(ProvisioningState.Idle);
+ sendNewAuditlog(newDescriptors);
+ m_processedAuditEvents = allDescriptors;
+ return;
+ }
+ else {
+ String value = (String) event.getProperties().get(AuditEvent.KEY_SUCCESS);
+ addStatusAttribute(KEY_LAST_INSTALL_SUCCESS, value);
+ if (Boolean.parseBoolean(value)) {
+ setProvisioningState(ProvisioningState.OK);
+ sendNewAuditlog(newDescriptors);
+ m_processedAuditEvents = allDescriptors;
+ return;
+ }
+ else {
+ setProvisioningState(ProvisioningState.Failed);
+ sendNewAuditlog(newDescriptors);
+ m_processedAuditEvents = allDescriptors;
+ return;
+ }
+ }
+ }
+ }
+
+ if (m_processedAuditEvents.isEmpty()) {
+ setProvisioningState(ProvisioningState.Idle);
+ }
+ sendNewAuditlog(newDescriptors);
+ m_processedAuditEvents = allDescriptors;
+ }
+ }
+
+ private void sendNewAuditlog(List<LogDescriptor> events) {
+ // Check whether there are actually events in the list.
+ boolean containsData = false;
+ for (LogDescriptor l : events) {
+ containsData |= (l.getRangeSet().getHigh() != 0);
+ }
+
+ if (containsData) {
+ Properties props = new Properties();
+ props.put(StatefulTargetObject.KEY_AUDITEVENTS, events);
+ m_repository.notifyChanged(this, TOPIC_AUDITEVENTS_CHANGED, props);
+ }
+ }
+
+ private void setRegistrationState(RegistrationState state) {
+ setStatus(KEY_REGISTRATION_STATE, state.toString());
+ }
+
+ private void setStoreState(StoreState state) {
+ setStatus(KEY_STORE_STATE, state.toString());
+ }
+
+ private void setProvisioningState(ProvisioningState state) {
+ setStatus(KEY_PROVISIONING_STATE, state.toString());
+ }
+
+ private void setStatus(String key, String status) {
+ if (!status.equals(getStatusAttribute(key))) {
+ addStatusAttribute(key, status);
+ handleStatechangeAutomation();
+ if (!m_inConstructor) {
+ m_repository.notifyChanged(this, TOPIC_STATUS_CHANGED);
+ }
+ }
+ }
+
+ private void handleStatechangeAutomation() {
+ if (getStoreState().equals(StoreState.Unapproved) && isRegistered() && getAutoApprove()) {
+ approve();
+ }
+ }
+
+ /**
+ * Verifies that this object should still be around. If the target is represents
+ * shows up in at least the target repository or the auditlog, it has a reason
+ * to exists; if not, it doesn't. When it is no longer necessary, it will remove itself
+ * from the parent repository.
+ * @return Whether or not this object should still exist.
+ */
+ boolean verifyExistence() {
+ synchronized(m_lock) {
+ if ((m_targetObject == null) && ((m_processedAuditEvents == null) || m_processedAuditEvents.isEmpty())) {
+ m_repository.removeStateful(this);
+ return false;
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Helper method for the delegate methods below: most of these delegate their calls to a
+ * <code>TargetObject</code>, but in order to do so, one must be present.
+ */
+ private void ensureTargetPresent() {
+ if ((m_targetObject == null)) {
+ throw new IllegalStateException("This StatefulTargetObject is not backed by a TargetObject.");
+ // NOTE: we do not check the isDeleted state; the TargetObject itself will notify the user of this.
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if ((o == null) || !(o instanceof StatefulTargetObject)) {
+ return false;
+ }
+ return getID().equals(((StatefulTargetObject) o).getID());
+ }
+
+ private void addStatusAttribute(String key, String value) {
+ m_attributes.put(key, value);
+ }
+
+ private String getStatusAttribute(String key) {
+ return m_attributes.get(key);
+ }
+
+ /* ******************
+ * Delegates to TargetObject
+ */
+
+ public String getID() {
+ return getStatusAttribute(KEY_ID);
+ }
+
+ public boolean isDeleted() {
+ return !verifyExistence();
+ }
+
+ public List<Distribution2TargetAssociation> getAssociationsWith(DistributionObject distribution) {
+ synchronized(m_lock) {
+ ensureTargetPresent();
+ return m_targetObject.getAssociationsWith(distribution);
+ }
+ }
+
+ public List<DistributionObject> getDistributions() {
+ synchronized(m_lock) {
+ ensureTargetPresent();
+ return m_targetObject.getDistributions();
+ }
+ }
+
+ public String addAttribute(String key, String value) {
+ synchronized(m_lock) {
+ ensureTargetPresent();
+ return m_targetObject.addAttribute(key, value);
+ }
+ }
+
+ public String addTag(String key, String value) {
+ synchronized(m_lock) {
+ ensureTargetPresent();
+ return m_targetObject.addTag(key, value);
+ }
+ }
+
+ public String getAttribute(String key) {
+ // retrieve from both
+ synchronized(m_lock) {
+ if (Arrays.binarySearch(KEYS_ALL, key) >= 0) {
+ return getStatusAttribute(key);
+ }
+ ensureTargetPresent();
+ return m_targetObject.getAttribute(key);
+ }
+ }
+
+ public Enumeration<String> getAttributeKeys() {
+ synchronized(m_lock) {
+ List<String> statusKeys = new ArrayList<String>();
+ for (String s : KEYS_ALL) {
+ statusKeys.add(s);
+ }
+ Enumeration<String> attributeKeys = null;
+ if (m_targetObject != null) {
+ attributeKeys = m_targetObject.getAttributeKeys();
+ }
+ return new ExtendedEnumeration<String>(attributeKeys, statusKeys, true);
+ }
+ }
+
+ public Dictionary<String, Object> getDictionary() {
+ // build our own dictionary
+ synchronized(m_lock) {
+ return new StatefulTargetObjectDictionary();
+ }
+ }
+
+ public String getTag(String key) {
+ synchronized(m_lock) {
+ ensureTargetPresent();
+ return m_targetObject.getTag(key);
+ }
+ }
+
+ public Enumeration<String> getTagKeys() {
+ synchronized(m_lock) {
+ ensureTargetPresent();
+ return m_targetObject.getTagKeys();
+ }
+ }
+
+ public boolean getAutoApprove() {
+ synchronized(m_lock) {
+ if (m_targetObject != null) {
+ return m_targetObject.getAutoApprove();
+ }
+ else {
+ return false;
+ }
+
+ }
+ }
+
+ public void setAutoApprove(boolean approve) {
+ synchronized(m_lock) {
+ ensureTargetPresent();
+ m_targetObject.setAutoApprove(approve);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T extends Associatable> void add(Association association, Class<T> clazz) {
+ synchronized(m_lock) {
+ ensureTargetPresent();
+ m_targetObject.add(association, clazz);
+ }
+ }
+
+ public <T extends Associatable> List<T> getAssociations(Class<T> clazz) {
+ synchronized(m_lock) {
+ ensureTargetPresent();
+ return m_targetObject.getAssociations(clazz);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T extends Associatable, A extends Association> List<A> getAssociationsWith(Associatable other, Class<T> clazz, Class<A> associationType) {
+ synchronized(m_lock) {
+ ensureTargetPresent();
+ return m_targetObject.getAssociationsWith(other, clazz, associationType);
+ }
+ }
+
+ public <T extends Associatable> boolean isAssociated(Object obj, Class<T> clazz) {
+ synchronized(m_lock) {
+ ensureTargetPresent();
+ return m_targetObject.isAssociated(obj, clazz);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T extends Associatable> void remove(Association association, Class<T> clazz) {
+ synchronized(m_lock) {
+ ensureTargetPresent();
+ m_targetObject.remove(association, clazz);
+ }
+ }
+
+ public String getDefinition() {
+ return "target-" + KEY_ID + "-" + getID();
+ }
+
+ private class ExtendedEnumeration<T> implements Enumeration<T> {
+ private Enumeration<T> m_source;
+ private List<T> m_extra;
+ private final boolean m_allowDuplicates;
+
+ ExtendedEnumeration(Enumeration<T> source, List<T> extra, boolean allowDuplicates) {
+ m_source = source;
+ m_extra = extra;
+ m_allowDuplicates = allowDuplicates;
+ }
+
+ public boolean hasMoreElements() {
+ boolean inSource = (m_source != null);
+ boolean inExtra = false;
+ if (m_extra != null) {
+ inExtra = !m_extra.isEmpty();
+ }
+ return inSource || inExtra;
+ }
+
+ public T nextElement() {
+ if (m_source != null) {
+ T result = m_source.nextElement();
+ if (!m_source.hasMoreElements()) {
+ m_source = null;
+ }
+ if (!m_allowDuplicates) {
+ m_extra.remove(result);
+ }
+ return result;
+ }
+ else if (!m_extra.isEmpty()) {
+ return m_extra.remove(0);
+ }
+ throw new NoSuchElementException();
+ }
+ }
+
+ private class StatefulTargetObjectDictionary extends Dictionary<String, Object> {
+ private final Dictionary<String, Object> m_dict;
+
+ StatefulTargetObjectDictionary() {
+ if (m_targetObject != null) {
+ m_dict = m_targetObject.getDictionary();
+ }
+ else {
+ m_dict = null;
+ }
+ }
+
+ @Override
+ public Enumeration<Object> elements() {
+ List<Object> statusVals = new ArrayList<Object>();
+ for (String key : KEYS_ALL) {
+ statusVals.add(getStatusAttribute(key));
+ }
+ Enumeration<Object> attributeVals = null;
+ if (m_dict != null) {
+ attributeVals = m_dict.elements();
+ }
+ return new ExtendedEnumeration<Object>(attributeVals, statusVals, true);
+ }
+
+ @Override
+ public Object get(Object key) {
+ for (String s : KEYS_ALL) {
+ if (s.equals(key)) {
+ return getStatusAttribute((String) key);
+ }
+ }
+ String tag = m_targetObject.getTag((String)key);
+ String attr = m_targetObject.getAttribute((String)key);
+ if (tag == null) {
+ return attr;
+ }
+ else if (attr == null) {
+ return tag;
+ }
+ else {
+ return new String[] {attr, tag};
+ }
+ }
+
+ @Override
+ public boolean isEmpty() {
+ // This is always false, since we always have the status attributes.
+ return false;
+ }
+
+ @Override
+ public Enumeration<String> keys() {
+ List<String> statusKeys = new ArrayList<String>();
+ for (String key : KEYS_ALL) {
+ statusKeys.add(key);
+ }
+ Enumeration<String> attributeKeys = null;
+ if (m_dict != null) {
+ attributeKeys = m_dict.keys();
+ }
+ return new ExtendedEnumeration<String>(attributeKeys, statusKeys, false);
+ }
+
+ @Override
+ public Object put(String key, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object remove(Object key) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int size() {
+ int result = 0;
+ Enumeration<String> keys = keys();
+ while (keys.hasMoreElements()) {
+ result++;
+ keys.nextElement();
+ }
+ return result;
+ }
+ }
+
+ public String getAssociationFilter(Map<String, String> properties) {
+ throw new UnsupportedOperationException("A StatefulTargetObject cannot return a filter; use the underlying TargetObject instead.");
+ }
+
+ public int getCardinality(Map<String, String> properties) {
+ throw new UnsupportedOperationException("A StatefulTargetObject cannot return a cardinality; use the underlying TargetObject instead.");
+ }
+
+ @SuppressWarnings("unchecked")
+ public Comparator getComparator() {
+ throw new UnsupportedOperationException("A StatefulTargetObject cannot return a comparator; use the underlying TargetObject instead.");
+ }
+}
\ No newline at end of file