Permalink
Browse files

Federation - Updated federation so that external projections are now …

…named using an alias and also added additional write tests
  • Loading branch information...
Horia Chiorean authored and rhauch committed Nov 7, 2012
1 parent b45f4a9 commit 5afd6692c8b714c71b2a5452d36dc7a72cb35b28
@@ -35,20 +35,21 @@
public interface FederationManager {
/**
- * Appends an external node at the given location to an existing node. If this is the first node appended to the existing
- * node, it will convert the existing node to a federated node.
+ * Creates an external projection by linking an internal node with an external node, from a given source using an optional alias.
+ * If this is the first node linked to the existing node, it will convert the existing node to a federated node.
*
- * @param absNodePath a {@code non-null} string representing the absolute path to an existing node.
+ * @param absNodePath a {@code non-null} string representing the absolute path to an existing internal node.
* @param sourceName a {@code non-null} string representing the name of an external source, configured in the repository.
- * @param externalLocation {@code non-null} string representing a path in the external source, where the external
- * node is expected to be located at.
- * @param filters an optional array of filters.
+ * @param externalPath a {@code non-null} string representing a path in the external source, where at which there is an external
+ * node that will be linked.
+ * @param alias an optional string representing the name under which the alias should be created. If not present, the {@code externalPath}
+ * will be used as the name of the alias.
*
* @throws RepositoryException if the repository cannot perform the operation.
- * TODO author=Horia Chiorean date=11/2/12 description=Define filters format
+ *
*/
- public void linkExternalLocation( String absNodePath,
- String sourceName,
- String externalLocation,
- String... filters ) throws RepositoryException;
+ public void createExternalProjection( String absNodePath,
+ String sourceName,
+ String externalPath,
+ String alias) throws RepositoryException;
}
@@ -43,17 +43,14 @@ public ModeShapeFederationManager( JcrSession session ) {
}
@Override
- public void linkExternalLocation( String absNodePath,
- String sourceName,
- String externalLocation,
- String... filters ) throws RepositoryException {
- //TODO author=Horia Chiorean date=11/2/12 description=Decide if this is the right level of abstraction
- //TODO author=Horia Chiorean date=11/2/12 description=Decide how to integrate with session transactions
- //TODO author=Horia Chiorean date=11/2/12 description=Decide how to use filters
+ public void createExternalProjection( String absNodePath,
+ String sourceName,
+ String externalPath,
+ String alias ) throws RepositoryException {
NodeKey key = session.getNode(absNodePath).key();
WritableSessionCache writableSessionCache = (WritableSessionCache)session.spawnSessionCache(false);
- writableSessionCache.linkExternalLocation(key, sourceName, externalLocation, filters);
+ writableSessionCache.createExternalProjection(key, sourceName, externalPath, alias);
writableSessionCache.save();
}
}
@@ -28,7 +28,6 @@
import javax.transaction.xa.XAResource;
import org.infinispan.schematic.SchematicEntry;
import org.infinispan.schematic.document.Document;
-import org.infinispan.schematic.document.EditableDocument;
/**
* A store which persists/retrieves documents.
@@ -107,21 +106,16 @@ public SchematicEntry storeDocument( String key,
public LocalDocumentStore localStore();
/**
- * Returns a reference to an external document at a given location.
+ * Creates an external projection from the federated node with the given key, towards the external node from the
+ * given path, from a source.
*
+ * @param federatedNodeKey a {@code non-null} string, the key of the federated node which will contain the projection
* @param sourceName a {@code non-null} string, the name of an external source.
- * @param documentLocation a {@code non-null} string, representing an external location
+ * @param externalPath a {@code non-null} string, representing a path towards a node from the source
*
- * @return an {@link EditableDocument} instance or {@code null} if such a document doesn't exist
+ * @return a {@code non-null} string representing the node key of the external node located at {@code externalPath}.
*/
- public EditableDocument getExternalDocumentAtLocation( String sourceName,
- String documentLocation );
-
- /**
- * Sets the federated node id as the parent of the document with the given id.
- *
- * @param federatedNodeKey a {@code non-null} string representing the id (key) of a federated node
- * @param documentKey a {@code non-null} string representing the id of a document.
- */
- public void setParent(String federatedNodeKey, String documentKey);
+ public String createExternalProjection( String federatedNodeKey,
+ String sourceName,
+ String externalPath );
}
@@ -37,6 +37,7 @@
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
+import org.infinispan.schematic.DocumentFactory;
import org.infinispan.schematic.Schematic;
import org.infinispan.schematic.SchematicEntry;
import org.infinispan.schematic.document.Binary;
@@ -49,6 +50,7 @@
import org.modeshape.common.text.NoOpEncoder;
import org.modeshape.common.text.TextDecoder;
import org.modeshape.common.text.TextEncoder;
+import org.modeshape.common.util.StringUtil;
import org.modeshape.jcr.ExecutionContext;
import org.modeshape.jcr.JcrLexicon;
import org.modeshape.jcr.api.value.DateTime;
@@ -159,11 +161,11 @@ void setLargeValueSize( long largeValueSize ) {
* Obtain the preferred {@link NodeKey key} for the parent of this node. Because a node can be used in more than once place,
* it may technically have more than one parent. Therefore, in such cases this method prefers the parent that is in the
* {@code primaryWorkspaceKey} and, if there is no such parent, the parent that is in the {@code secondaryWorkspaceKey}.
- *
+ *
* @param document the document for the node; may not be null
* @param primaryWorkspaceKey the key for the workspace in which the parent should preferrably exist; may be null
* @param secondaryWorkspaceKey the key for the workspace in which the parent should exist if not in the primary workspace;
- * may be null
+ * may be null
* @return the key representing the preferred parent, or null if the document contains no parent reference or if the parent
* reference(s) do not have the specified workspace keys
*/
@@ -784,19 +786,8 @@ public ChildReferences getChildReferences( WorkspaceCache cache,
// Materialize the ChildReference objects in the 'children' document ...
List<ChildReference> internalChildRefsList = childReferencesListFromArray(children);
+ // Materialize the ChildReference objects in the 'federated segments' document ...
List<ChildReference> externalChildRefsList = childReferencesListFromArray(externalSegments);
- if (externalSegments != null) {
- // Materialize the ChildReference objects in the 'federated segments' document ...
- if (!externalChildRefsList.isEmpty()) {
- String federatedNodeKey = document.getString(KEY);
- assert federatedNodeKey != null;
- // set the parent back reference for each of the external segments
- //TODO author=Horia Chiorean date=11/6/12 description=This is probably only a temporary solution
- for (ChildReference externalChild : externalChildRefsList) {
- documentStore.setParent(federatedNodeKey, externalChild.getKey().toString());
- }
- }
- }
// Now look at the 'childrenInfo' document for info about the next block of children ...
ChildReferencesInfo info = getChildReferencesInfo(document);
@@ -982,7 +973,7 @@ private void updateReferrers( EditableDocument owningDocument,
/**
* Given the lists of added & removed referrers (which may contain duplicates), compute the delta with which the count has to
* be updated in the document
- *
+ *
* @param addedReferrers the list of referrers that was added
* @param removedReferrers the list of referrers that was removed
* @return a map(nodekey, delta) pairs
@@ -993,8 +984,8 @@ private void updateReferrers( EditableDocument owningDocument,
Set<NodeKey> addedReferrersUnique = new HashSet<NodeKey>(addedReferrers);
for (NodeKey addedReferrer : addedReferrersUnique) {
- int referrersCount = Collections.frequency(addedReferrers, addedReferrer)
- - Collections.frequency(removedReferrers, addedReferrer);
+ int referrersCount = Collections.frequency(addedReferrers, addedReferrer) - Collections.frequency(removedReferrers,
+ addedReferrer);
referrersCountDelta.put(addedReferrer, referrersCount);
}
@@ -1064,7 +1055,9 @@ protected Object valueToDocument( Object value,
if (value instanceof Reference) {
Reference ref = (Reference)value;
String key = ref.isWeak() ? "$wref" : "$ref";
- String refString = value instanceof NodeKeyReference ? ((NodeKeyReference)value).getNodeKey().toString() : this.strings.create(ref);
+ String refString =
+ value instanceof NodeKeyReference ? ((NodeKeyReference)value).getNodeKey().toString() : this.strings.create(
+ ref);
boolean isForeign = (value instanceof NodeKeyReference) && ((NodeKeyReference)value).isForeign();
return Schematic.newDocument(key, refString, "$foreign", isForeign);
}
@@ -1097,7 +1090,7 @@ protected final String keyForBinaryReferenceDocument( String sha1 ) {
/**
* Increment the reference count for the stored binary value with the supplied SHA-1 hash.
- *
+ *
* @param binaryKey the key for the binary value; never null
* @param unusedBinaryKeys the set of binary keys that are considered unused; may be null
*/
@@ -1124,7 +1117,7 @@ protected void incrementBinaryReferenceCount( BinaryKey binaryKey,
/**
* Decrement the reference count for the binary value.
- *
+ *
* @param fieldValue the value in the document that may contain a binary value reference; may be null
* @param unusedBinaryKeys the set of binary keys that are considered unused; may be null
* @return true if the binary value is no longer referenced, or false otherwise
@@ -1299,7 +1292,7 @@ protected Object resolveLargeValue( String sha1 ) {
* transactional context or it must be followed by a session.save call, otherwise there might be inconsistencies between what
* a session sees as "persisted" state and the reality.
* </p>
- *
+ *
* @param key
* @param document
* @param targetCountPerBlock
@@ -1395,16 +1388,16 @@ protected void optimizeChildrenBlocks( NodeKey key,
* transactional context or it must be followed by a session.save call, otherwise there might be inconsistencies between what
* a session sees as "persisted" state and the reality.
* </p>
- *
+ *
* @param key the key for the document whose children are to be split; may not be null
* @param document the document whose children are to be split; may not be null
* @param children the children that are to be split; may not be null
* @param targetCountPerBlock the goal for the number of children in each block; must be positive
* @param tolerance a tolerance that when added to and subtraced from the <code>targetCountPerBlock</code> gives an acceptable
- * range for the number of children; must be positive but smaller than <code>targetCountPerBlock</code>
+ * range for the number of children; must be positive but smaller than <code>targetCountPerBlock</code>
* @param isFirst true if the supplied document is the first node document, or false if it is a block document
* @param nextBlock the key for the next block of children; may be null if the supplied document is the last document and
- * there is no next block
+ * there is no next block
* @return true if the children were split, or false if no changes were made
*/
protected boolean splitChildren( NodeKey key,
@@ -1503,13 +1496,13 @@ protected boolean splitChildren( NodeKey key,
* transactional context or it must be followed by a session.save call, otherwise there might be inconsistencies between what
* a session sees as "persisted" state and the reality.
* </p>
- *
+ *
* @param key the key for the document whose children are to be merged with the next block; may not be null
* @param document the document to be modified with the next block's children; may not be null
* @param children the children into which are to be merged the next block's children; may not be null
* @param isFirst true if the supplied document is the first node document, or false if it is a block document
* @param nextBlock the key for the next block of children; may be null if the supplied document is the last document and
- * there is no next block
+ * there is no next block
* @return the key for the block of children that is after blocks that are removed; may be null if the supplied document is
* the last block
*/
@@ -1576,7 +1569,7 @@ protected String mergeChildren( NodeKey key,
/**
* Checks if the given document is already locked
- *
+ *
* @param doc the document
* @return true if the change was made successfully, or false otherwise
*/
@@ -1585,28 +1578,41 @@ public boolean isLocked( EditableDocument doc ) {
}
/**
- * Given an existing document appends one or more external documents to it by using the
- * {@link org.modeshape.jcr.federation.FederatedDocumentStore} to retrieve the references to the documents at that location.
- *
- * @param document a {@code non-null} {@link EditableDocument} representing the document of a local node to which one or more
- * external documents should be added.
- * @param sourceName the name of the source that contains the external documents
- * @param externalLocations the locations of the external documents that should be added to the supplied document
+ * Given an existing document adds a new federated segment with the given alias pointing to the external document located
+ * at {@code externalPath}
+ *
+ * @param document a {@code non-null} {@link EditableDocument} representing the document of a local node to which the federated
+ * segment should be appended.
+ * @param sourceName a {@code non-null} string, the name of the source where {@code externalPath} will be resolved
+ * @param externalPath a {@code non-null} string the location in the external source which points to an external node
+ * @param alias an optional string representing the name under which the federated segment will be linked. In effect, this
+ * represents the name of a child reference. If not present, the {@code externalPath} will be used.
+ *
+ * Note that the name of the federated segment (either coming from {@code externalPath} or {@code alias}) should not
+ * contain the "/" character. If it does, this will be removed.
*/
- public void addExternalDocuments( EditableDocument document,
- String sourceName,
- String... externalLocations ) {
+ public void addFederatedSegment( EditableDocument document,
+ String sourceName,
+ String externalPath,
+ String alias ) {
EditableArray federatedSegmentsArray = document.getArray(FEDERATED_SEGMENTS);
if (federatedSegmentsArray == null) {
federatedSegmentsArray = Schematic.newArray();
document.set(FEDERATED_SEGMENTS, federatedSegmentsArray);
}
- for (String externalLocation : externalLocations) {
- EditableDocument externalDocument = documentStore.getExternalDocumentAtLocation(sourceName, externalLocation);
- if (externalDocument != null) {
- federatedSegmentsArray.add(externalDocument);
+ String parentKey = document.getString(KEY);
+ String externalNodeKey = documentStore.createExternalProjection(parentKey, sourceName, externalPath);
+ if (!StringUtil.isBlank(externalNodeKey)) {
+ String segmentName = !StringUtil.isBlank(alias) ? alias : externalPath;
+ if (segmentName.endsWith("/")) {
+ segmentName = segmentName.substring(0, segmentName.length() - 1);
+ }
+ if (segmentName.contains("/")) {
+ segmentName = segmentName.substring(segmentName.lastIndexOf("/") + 1);
}
+ EditableDocument federatedSegment = DocumentFactory.newDocument(KEY, externalNodeKey, NAME, segmentName);
+ federatedSegmentsArray.add(federatedSegment);
}
}
}
@@ -30,7 +30,6 @@
import org.infinispan.schematic.SchematicDb;
import org.infinispan.schematic.SchematicEntry;
import org.infinispan.schematic.document.Document;
-import org.infinispan.schematic.document.EditableDocument;
/**
* An implementation of {@link DocumentStore} which always uses the local cache to store/retrieve data and which provides some
@@ -146,9 +145,10 @@ public void setLocalSourceKey( String sourceKey ) {
}
@Override
- public EditableDocument getExternalDocumentAtLocation( String sourceName,
- String documentLocation ) {
- throw new UnsupportedOperationException("External documents are not supported in the local document store");
+ public String createExternalProjection( String federatedNodeKey,
+ String sourceName,
+ String externalPath ) {
+ throw new UnsupportedOperationException("External projections are not supported in the local document store");
}
/**
@@ -159,10 +159,4 @@ public EditableDocument getExternalDocumentAtLocation( String sourceName,
public Cache<String, SchematicEntry> localCache() {
return database.getCache();
}
-
- @Override
- public void setParent( String federatedNodeKey,
- String documentKey ) {
- // do nothing
- }
}
Oops, something went wrong.

0 comments on commit 5afd669

Please sign in to comment.