You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pp...@apache.org on 2010/06/17 01:22:31 UTC
svn commit: r955425 -
/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/
Author: ppoddar
Date: Wed Jun 16 23:22:31 2010
New Revision: 955425
URL: http://svn.apache.org/viewvc?rev=955425&view=rev
Log:
OPENJPA-1686: Define generic persistent graph and relation. Implement graph as a set of edges.
Added:
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/AbstractGraph.java (with props)
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/Graph.java (with props)
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/PersistentGraph.java (with props)
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/PersistentRelation.java
- copied, changed from r954593, openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/Relation.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/RelationGraph.java (with props)
Removed:
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/Vertex.java
Modified:
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/City.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/People.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/Relation.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/TestPersistentGraph.java
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/AbstractGraph.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/AbstractGraph.java?rev=955425&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/AbstractGraph.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/AbstractGraph.java Wed Jun 16 23:22:31 2010
@@ -0,0 +1,47 @@
+/*
+ * 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.openjpa.persistence.graph;
+
+import java.util.AbstractSet;
+import java.util.Set;
+
+/**
+ * Abstract implementation of a {@linkplain Graph} borrows from {@link AbstractSet abstract} implementation of
+ * {@link Set}. The extended {@link Set#remove(Object) remove()} semantics accounts for
+ * {@link Graph#delink(Object, Object) removal} of all relationship to the removed element.
+ *
+ * @author Pinaki Poddar
+ *
+ * @param <E> type of element of the graph.
+ */
+public abstract class AbstractGraph<E> extends AbstractSet<E> implements Graph<E> {
+ /**
+ * Removing an element from this graph has the side effect of removing all
+ * relations directed to the removed element.
+ */
+ @Override
+ public boolean remove(Object e) {
+ E node = (E)e;
+ Set<Relation<E, E>> rs = getRelationsTo(node);
+ for (Relation<E,E> r : rs) {
+ delink(r.getSource(), node);
+ }
+ return super.remove(e);
+ }
+}
Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/AbstractGraph.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/City.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/City.java?rev=955425&r1=955424&r2=955425&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/City.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/City.java Wed Jun 16 23:22:31 2010
@@ -18,20 +18,20 @@
*/
package org.apache.openjpa.persistence.graph;
+import java.io.Serializable;
+
import javax.persistence.Entity;
import javax.persistence.Id;
/**
* A simple persistent entity to become member of a graph.
- * In this style, a type has to extend {@linkplain Vertex} - an abstract persistent type.
- * This persistent type has its own identity.
*
* @author Pinaki Poddar
*
*/
@SuppressWarnings("serial")
@Entity
-public class City extends Vertex<City> {
+public class City implements Serializable {
@Id
private String name;
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/Graph.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/Graph.java?rev=955425&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/Graph.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/Graph.java Wed Jun 16 23:22:31 2010
@@ -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.openjpa.persistence.graph;
+
+import java.util.Set;
+
+/**
+ * Graph is an extended {@link java.util.Set Set} that is aware of {@link Relation relationship}
+ * between its elements. The linkage between two elements is represented by a {@link Relation relation}.
+ * <br>
+ * The extended behavior of Set allows two member elements to be {@linkplain Graph#link(Object, Object) linked}
+ * or {@linkplain Graph#delink(Object, Object) delinked}.
+ *
+ * @param <E> Type of element of the graph
+ *
+ *
+ * @author Pinaki Poddar
+ *
+ */
+public interface Graph<E> extends Set<E> {
+ /**
+ * Links the pair of given vertices.
+ * If the pair is already linked then the existing relation is returned.
+ * If either of the vertices are currently non a member of this graph,
+ * then they are added to the graph as a side-effect of linking.
+ *
+ * @param source non-null source node
+ * @param target non-null target node
+ *
+ * @param <V1> generic type of source node
+ * @param <V2> generic type of target node
+ *
+ * @return a relation
+ */
+ public <V1 extends E, V2 extends E> Relation<V1, V2> link(V1 source, V2 target);
+
+ /**
+ * Breaks the relation between the given pair of nodes.
+ *
+ * @param source non-null source node
+ * @param target non-null target node
+ *
+ * @param <V1> generic type of source node
+ * @param <V2> generic type of target node
+ *
+ * @return the existing relation, if any, that had been broken. null otherwise.
+ */
+ public <V1 extends E, V2 extends E> Relation<V1, V2> delink(V1 source, V2 target);
+
+ /**
+ * Gets the directed relation between the given pair of nodes, if exists.
+ *
+ * @param source non-null source node
+ * @param target non-null target node
+ *
+ * @param <V1> generic type of source node
+ * @param <V2> generic type of target node
+ *
+ * @return a relation between the nodes, if exists. null otherwise.
+ */
+ public <V1 extends E, V2 extends E> Relation<V1, V2> getRelation(V1 source, V2 target);
+
+ /**
+ * Gets the nodes that are directly reachable from the given source node.
+ *
+ * @return set of target nodes. Empty set if the given source node is not connected to any other nodes.
+ */
+ public Set<E> getTargets(E source);
+
+
+ /**
+ * Gets the source nodes that are directly connected to the given target node.
+ *
+ * @return set of source nodes. Empty set if the given target node is not connected from any node.
+ */
+ public Set<E> getSources(E target);
+
+ /**
+ * Gets all the relations originating from the given source.
+ * @param <V>
+ * @param source
+ * @return
+ */
+ public <V extends E> Set<Relation<V,E>> getRelationsFrom(V source);
+
+ /**
+ * Gets all the relations terminating on the given target.
+ * @param <V>
+ * @param target
+ * @return
+ */
+ public <V extends E> Set<Relation<E,V>> getRelationsTo(V target);
+}
Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/Graph.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/People.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/People.java?rev=955425&r1=955424&r2=955425&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/People.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/People.java Wed Jun 16 23:22:31 2010
@@ -18,23 +18,24 @@
*/
package org.apache.openjpa.persistence.graph;
+import java.io.Serializable;
+
import javax.persistence.Entity;
import javax.persistence.Id;
/**
* A simple persistent entity to become member of a graph.
- * In this style, a type has to extend {@linkplain Vertex} - an abstract persistent type.
- * This persistent type has its own identity.
*
* @author Pinaki Poddar
*
*/
@SuppressWarnings("serial")
@Entity
-public class People extends Vertex<People>{
+public class People implements Serializable {
@Id
private long ssn;
private String name;
+
public long getSsn() {
return ssn;
}
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/PersistentGraph.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/PersistentGraph.java?rev=955425&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/PersistentGraph.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/PersistentGraph.java Wed Jun 16 23:22:31 2010
@@ -0,0 +1,53 @@
+/*
+ * 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.openjpa.persistence.graph;
+
+import java.io.Serializable;
+
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.MappedSuperclass;
+
+/**
+ * Persistent Graph is a marker for persistent version of a {@link Graph}.
+ * <br>
+ * A persistent graph does not declare how the persistent state of the graph is captured and hence is abstract.
+ * But Persistent Graph is unique to be persistent in a JPA sense, because JPA does <em>not</em> represent
+ * container instances such as {@link java.util.Set} or {@link java.util.List} as <em>first class</em> type --
+ * i.e. their instances do not carry a persistent identity. But declaring a graph as persistent type amounts
+ * to represent the graph as a first class persistent type with its own persistent identity.
+ * <br>
+ * Persistent Graph defines a auto-generated persistent identity.
+ *
+ * @author Pinaki Poddar
+ *
+ * @param <E> type of element.
+ */
+@SuppressWarnings("serial")
+@MappedSuperclass
+public abstract class PersistentGraph<E> extends AbstractGraph<E> implements Serializable {
+
+ @Id
+ @GeneratedValue
+ private long id;
+
+ public final long getId() {
+ return id;
+ }
+}
Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/PersistentGraph.java
------------------------------------------------------------------------------
svn:eol-style = native
Copied: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/PersistentRelation.java (from r954593, openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/Relation.java)
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/PersistentRelation.java?p2=openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/PersistentRelation.java&p1=openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/Relation.java&r1=954593&r2=955425&rev=955425&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/Relation.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/PersistentRelation.java Wed Jun 16 23:22:31 2010
@@ -30,17 +30,20 @@ import javax.persistence.ManyToMany;
import javax.persistence.OneToOne;
/**
- * Generic, directed, attributed Relation as a first-class entity.
+ * Generic, directed, attributed Relation as a first-class, persistent entity.
* <br>
* A relation is
* <ol>
- * <LI>generic because the vertices it links are generically typed.
- * <LI>directed because it distinguishes the two end points as source and target.
+ * <LI>generic because Relation type is parameterized with the type of vertices it links.
+ * <LI>directed because it distinguishes the two vertices as source and target.
* <LI>attributed because any arbitrary name-value pair can be associated with a relation.
* </ol>
+ * A relation is made persistence capable by annotating its generic source and target as persistent entity.
+ * A relation is also a <em>first-class</em> entity having its own persistent identifier.
+ * <br>
* A relation is immutable in terms of its two vertices. The properties
- * attached to a relation can change.
- *
+ * attached to a relation, however, can change.
+ * <br>
* @param <V1> the type of <em>source</em> vertex linked by this relation.
* @param <V2> the type of <em>target</em> vertex linked by this relation.
*
@@ -49,7 +52,7 @@ import javax.persistence.OneToOne;
*/
@SuppressWarnings("serial")
@Entity
-public class Relation<V1,V2> implements Serializable {
+public class PersistentRelation<V1,V2> implements Relation<V1,V2>, Serializable {
/**
* Relation is a first class object with its own identifier.
*/
@@ -60,14 +63,16 @@ public class Relation<V1,V2> implements
/**
* A Relation must have a non-null vertex as source.
*/
- @OneToOne(optional=false)
- private Vertex<V1> source;
+ @OneToOne(optional=false, targetEntity=Entity.class,
+ cascade={CascadeType.PERSIST,CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH})
+ private V1 source;
/**
- * A Relation must have a non-null vertex as source.
+ * A Relation may have a non-null vertex as target.
*/
- @OneToOne(optional=false)
- private Vertex<V2> target;
+ @OneToOne(optional=true, targetEntity=Entity.class,
+ cascade={CascadeType.PERSIST,CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH})
+ private V2 target;
/**
* The properties of a Relation is a set of key-value pairs and is declared as
@@ -102,18 +107,18 @@ public class Relation<V1,V2> implements
/**
* Special constructor for byte code enhancement.
*/
- protected Relation() {
+ protected PersistentRelation() {
}
/**
* A relation is immutable in terms of two vertices it connects.
- * Either vertex must not be null.
+ *
+ * @param s source vertex must not be null.
+ * @param t target vertex may or may not be null.
*/
- public Relation(Vertex<V1> s, Vertex<V2> t) {
+ public PersistentRelation(V1 s, V2 t) {
if (s == null)
throw new NullPointerException("Can not create relation from a null source vertex");
- if (t == null)
- throw new NullPointerException("Can not create relation to a null target vertex");
source = s;
target = t;
attrs = new Properties();
@@ -128,15 +133,15 @@ public class Relation<V1,V2> implements
/**
* Gets the immutable source vertex.
- */
- public Vertex<V1> getSource() {
+ */
+ public V1 getSource() {
return source;
}
/**
* Gets the immutable target vertex.
- */
- public Vertex<V2> getTarget() {
+ */
+ public V2 getTarget() {
return target;
}
@@ -181,4 +186,8 @@ public class Relation<V1,V2> implements
attrs.remove(attr);
return this;
}
+
+ public String toString() {
+ return source + "->" + target;
+ }
}
Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/Relation.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/Relation.java?rev=955425&r1=955424&r2=955425&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/Relation.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/Relation.java Wed Jun 16 23:22:31 2010
@@ -18,167 +18,76 @@
*/
package org.apache.openjpa.persistence.graph;
-import java.io.Serializable;
import java.util.Properties;
-import javax.persistence.CascadeType;
-import javax.persistence.Entity;
-import javax.persistence.FetchType;
-import javax.persistence.GeneratedValue;
-import javax.persistence.Id;
-import javax.persistence.ManyToMany;
-import javax.persistence.OneToOne;
-
/**
- * Generic, directed, attributed Relation as a first-class entity.
+ * Generic, directed, attributed Relation.
* <br>
* A relation is
* <ol>
- * <LI>generic because the vertices it links are generically typed.
- * <LI>directed because it distinguishes the two end points as source and target.
- * <LI>attributed because any arbitrary name-value pair can be associated with a relation.
+ * <LI>generic because Relation type is parameterized with the type of vertices it links.
+ * <LI>directed because it distinguishes the two vertices as source and target.
+ * <LI>attributed because any arbitrary key-value pair can be associated with a relation.
* </ol>
+ * <br>
* A relation is immutable in terms of its two vertices. The properties
- * attached to a relation can change.
- *
+ * associated to a relation, however, can change.
+ * <br>
* @param <V1> the type of <em>source</em> vertex linked by this relation.
* @param <V2> the type of <em>target</em> vertex linked by this relation.
*
* @author Pinaki Poddar
*
*/
-@SuppressWarnings("serial")
-@Entity
-public class Relation<V1,V2> implements Serializable {
+public interface Relation<V1,V2> {
/**
- * Relation is a first class object with its own identifier.
- */
- @Id
- @GeneratedValue
- private long id;
-
- /**
- * A Relation must have a non-null vertex as source.
- */
- @OneToOne(optional=false)
- private Vertex<V1> source;
-
- /**
- * A Relation must have a non-null vertex as source.
+ * Gets the immutable source vertex.
+ *
+ * @return a non-null source vertex.
*/
- @OneToOne(optional=false)
- private Vertex<V2> target;
+ public V1 getSource();
/**
- * The properties of a Relation is a set of key-value pairs and is declared as
- * <code>java.util.Properties</code>.
- * <br>
- * Declaring the key-value pairs as <code>java.util.Properties</code> makes OpenJPA
- * assume that both key and value will be stored in database as String.
- * This is not <em>strictly</em> correct because <code>java.util.Properties</code>
- * declares its key and value as <code>java.lang.Object</code>. Hence it is possible for an application
- * to insert key and/or value that are not a String but that type information will not be preserved in
- * the database. Subsequently, when loaded from database the key and value
- * both will appear as String and hence it becomes the application's responsibility to decode the
- * Strings back to the actual type. While this provision loses type information, it allows the
- * database record to be readable and more importantly supports query that are predicated on
- * (equality only) key-value pairs.
- * <br>
- * Another possibility to express key-value pair as
- * <br>
- * <code>Map<String,Serializable> attrs;</code>
- * <br>
- * This will serialize the values but preserve their types. The down-side is neither a query can be
- * predicated on value nor are the database records readable.
- * <br>
- * The third alternative is a Map where keys are String and values are Object
- * <br>
- * <code>Map<String,Object> attrs;</code>
- * This leads to the whole map being serialized as a single blob of data.
+ * Gets the immutable target vertex.
+ * Unlike source, a target for a relation may be null.
+ *
+ * @return a target vertex. May be null.
*/
- @ManyToMany(cascade={CascadeType.ALL},fetch=FetchType.LAZY)
- private Properties attrs;
+ public V2 getTarget();
- /**
- * Special constructor for byte code enhancement.
- */
- protected Relation() {
- }
/**
- * A relation is immutable in terms of two vertices it connects.
- * Either vertex must not be null.
- */
- public Relation(Vertex<V1> s, Vertex<V2> t) {
- if (s == null)
- throw new NullPointerException("Can not create relation from a null source vertex");
- if (t == null)
- throw new NullPointerException("Can not create relation to a null target vertex");
- source = s;
- target = t;
- attrs = new Properties();
- }
-
- /**
- * Gets generated persistent identity.
+ * Adds the given key-value pair, overwriting any prior value associated to the same key.
+ *
+ * @return the same relation for <em>fluent</em> method-chaining
*/
- public long getId() {
- return id;
- }
-
- /**
- * Gets the immutable source vertex.
- */
- public Vertex<V1> getSource() {
- return source;
- }
-
- /**
- * Gets the immutable target vertex.
- */
- public Vertex<V2> getTarget() {
- return target;
- }
+ public Relation<V1,V2> addAttribute(String key, Object value);
/**
- * Affirms if the given attribute is associated with this relation.
+ * Affirms if an attribute value has been associated with the given key.
+ *
*/
- public boolean hasAttribute(String attr) {
- return attrs.containsKey(attr);
- }
+ public boolean hasAttribute(String key);
/**
* Gets the value of the given attribute.
*
* @return value of the given attribute. A null value does not distinguish whether
* the attribute was set to a null value or the attribute was absent.
- */
- public Object getAttribute(String attr) {
- return attrs.get(attr);
- }
-
- public Properties getAttributes() {
- return attrs;
- }
-
- /**
- * Adds the given key-value pair, overwriting any prior association to the same attribute.
*
- * @return the same relation for fluent method-chaining
+ * @see #hasAttribute(String)
*/
- public Relation<V1,V2> addAttribute(String attr, Object v) {
- attrs.put(attr, v);
- return this;
- }
+ public Object getAttribute(String key);
/**
* Removes the given attribute.
*
- * @return value of the given attribute that just has been removed. A null value does not
- * distinguish whether the attribute was set to a null value or the attribute was absent.
+ * @return the modified relation for <em>fluent</em> method chaining.
+ */
+ public Relation<V1,V2> removeAttribute(String key);
+
+ /**
+ * Gets the key-value pairs associated with this relation.
*/
- public Relation<V1,V2> removeAttribute(String attr) {
- attrs.remove(attr);
- return this;
- }
+ public Properties getAttributes();
}
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/RelationGraph.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/RelationGraph.java?rev=955425&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/RelationGraph.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/RelationGraph.java Wed Jun 16 23:22:31 2010
@@ -0,0 +1,163 @@
+/*
+ * 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.openjpa.persistence.graph;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.OneToMany;
+
+/**
+ * RelationGraph is a first-class persistent entity that express its persistent state as a set of
+ * {@link Relation persistent relations}.
+ *
+ * @author Pinaki Poddar
+ *
+ */
+
+@SuppressWarnings("serial")
+@Entity
+public class RelationGraph<E> extends PersistentGraph<E> {
+ @OneToMany(cascade={CascadeType.PERSIST,CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH})
+ private Set<PersistentRelation<E,E>> relations = new HashSet<PersistentRelation<E,E>>();
+
+ /*
+ * Links the given vertices, unless they are already connected.
+ *
+ * @param source non-null source vertex
+ * @param target non-null target vertex
+ *
+ * @see org.apache.openjpa.persistence.graph.Graph#link(V1, V2)
+ */
+ public <V1 extends E,V2 extends E> Relation<V1,V2> link(V1 source, V2 target) {
+ if (source == null)
+ throw new NullPointerException("Can not link from a null source vertex");
+ if (target == null)
+ throw new NullPointerException("Can not link to a null target vertex");
+
+ Relation<V1,V2> r = getRelation(source, target);
+ if (r == null) {
+ r = new PersistentRelation<V1, V2>(source, target);
+ relations.add((PersistentRelation<E, E>) r);
+ }
+ return r;
+
+ }
+
+ /*
+ * Delinks the given vertices, if they are currently connected.
+ *
+ *
+ * @see org.apache.openjpa.persistence.graph.Graph#delink(V1, V2)
+ */
+ public <V1 extends E,V2 extends E> Relation<V1,V2> delink(V1 source, V2 target) {
+ Relation<V1,V2> r = getRelation(source, target);
+ if (r != null) {
+ relations.remove(r);
+ }
+ return r;
+
+ }
+
+ /*
+ * Get the relation between the given vertex.
+ *
+ * @see org.apache.openjpa.persistence.graph2.Graph#getRelation(V1, V2)
+ */
+ public <V1 extends E,V2 extends E> Relation<V1,V2> getRelation(V1 source, V2 target) {
+ for (Relation<?,?> r : relations) {
+ if (r.getSource().equals(source) && r.getTarget() != null && r.getTarget().equals(target)) {
+ return (Relation<V1,V2>)r;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Iterator over the nodes of this graph.
+ */
+ public Iterator<E> iterator() {
+ return getNodes().iterator();
+ }
+
+ public int size() {
+ return 0;
+ }
+
+ @Override
+ public <V extends E> Set<Relation<V, E>> getRelationsFrom(V source) {
+ Set<Relation<V,E>> rs = new HashSet<Relation<V,E>>();
+ for (Relation<E,E> r : relations) {
+ if (r.getSource().equals(source) && r.getTarget() != null)
+ rs.add((Relation<V,E>)r);
+ }
+ return rs;
+ }
+
+ @Override
+ public <V extends E> Set<Relation<E, V>> getRelationsTo(V target) {
+ Set<Relation<E, V>> rs = new HashSet<Relation<E, V>>();
+ for (Relation<?,?> r : relations) {
+ if (r.getTarget() != null && r.getTarget().equals(target))
+ rs.add((Relation<E, V>)r);
+ }
+ return rs;
+ }
+
+ @Override
+ public Set<E> getSources(Object target) {
+ Set<E> sources = new HashSet<E>();
+ for (Relation<E,E> r : relations) {
+ if (r.getTarget() != null && r.getTarget().equals(target))
+ sources.add(r.getSource());
+ }
+ return sources;
+ }
+
+ @Override
+ public Set<E> getTargets(Object source) {
+ Set<E> targets = new HashSet<E>();
+ for (Relation<E,E> r : relations) {
+ if (r.getSource().equals(source) && r.getTarget() != null)
+ targets.add(r.getTarget());
+ }
+ return targets;
+ }
+
+ public Set<E> getNodes() {
+ Set all = new HashSet();
+ for (Relation<?,?> r : relations) {
+ all.add(r.getSource());
+ if (r.getTarget() != null)
+ all.add(r.getTarget());
+ }
+ return all;
+ }
+
+ @Override
+ public boolean add(E e) {
+ if (contains(e))
+ return false;
+ relations.add(new PersistentRelation<E,E>(e,null));
+ return true;
+ }
+}
Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/RelationGraph.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/TestPersistentGraph.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/TestPersistentGraph.java?rev=955425&r1=955424&r2=955425&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/TestPersistentGraph.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/TestPersistentGraph.java Wed Jun 16 23:22:31 2010
@@ -32,13 +32,11 @@ import org.apache.openjpa.jdbc.meta.Mapp
import org.apache.openjpa.jdbc.meta.ValueHandler;
import org.apache.openjpa.jdbc.meta.strats.HandlerFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.HandlerHandlerMapTableFieldStrategy;
-import org.apache.openjpa.jdbc.meta.strats.RelationCollectionInverseKeyFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.UntypedPCValueHandler;
import org.apache.openjpa.kernel.QueryHints;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.meta.MetaDataRepository;
-import org.apache.openjpa.persistence.OpenJPAPersistence;
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
/**
@@ -80,23 +78,23 @@ public class TestPersistentGraph extends
};
private EntityManager em;
-
+ private PersistentGraph<Object> graph;
+
public void setUp() throws Exception {
- super.setUp(CLEAR_TABLES, Vertex.class, Relation.class, People.class, City.class);
+ super.setUp(CLEAR_TABLES, PersistentGraph.class, RelationGraph.class,
+ PersistentRelation.class, People.class, City.class);
em = emf.createEntityManager();
- createData();
+ graph = createData();
em.clear();
}
-
+
/**
* Verifies that fields are mapped with expected strategy or value handlers.
*/
public void testMapping() {
- assertStrategy(People.class, "relations", RelationCollectionInverseKeyFieldStrategy.class, null);
- assertStrategy(City.class, "relations", RelationCollectionInverseKeyFieldStrategy.class, null);
- assertStrategy(Relation.class, "source", HandlerFieldStrategy.class, UntypedPCValueHandler.class);
- assertStrategy(Relation.class, "target", HandlerFieldStrategy.class, UntypedPCValueHandler.class);
- assertStrategy(Relation.class, "attrs", HandlerHandlerMapTableFieldStrategy.class, null);
+ assertStrategy(PersistentRelation.class, "source", HandlerFieldStrategy.class, UntypedPCValueHandler.class);
+ assertStrategy(PersistentRelation.class, "target", HandlerFieldStrategy.class, UntypedPCValueHandler.class);
+ assertStrategy(PersistentRelation.class, "attrs", HandlerHandlerMapTableFieldStrategy.class, null);
}
private void printMapping(FieldMapping fm) {
@@ -111,7 +109,7 @@ public class TestPersistentGraph extends
}
FieldMapping getFieldMapping(Class<?> pcClass, String field) {
- MappingRepository repos = (MappingRepository) OpenJPAPersistence.cast(emf).getConfiguration()
+ MappingRepository repos = (MappingRepository) emf.getConfiguration()
.getMetaDataRepositoryInstance();
ClassMapping cmd = repos.getMapping(pcClass, null, true);
assertNotNull("No metadata found for " + pcClass, cmd);
@@ -123,7 +121,7 @@ public class TestPersistentGraph extends
/**
* Asserts that the given field of the given class has been mapped with the
- * given straegy or value handler.
+ * given strategy or value handler.
*/
void assertStrategy(Class<?> pcClass, String field, Class<? extends FieldStrategy> strategy,
Class<? extends ValueHandler> handler) {
@@ -151,7 +149,7 @@ public class TestPersistentGraph extends
}
FieldStrategy getStrategy(Class<?> cls, String field) {
- MetaDataRepository repos = OpenJPAPersistence.cast(emf).getConfiguration().getMetaDataRepositoryInstance();
+ MetaDataRepository repos = emf.getConfiguration().getMetaDataRepositoryInstance();
ClassMetaData cmd = repos.getMetaData(cls, null, true);
assertNotNull("No metadat found for " + cls, cmd);
FieldMetaData fmd = cmd.getField(field);
@@ -168,6 +166,9 @@ public class TestPersistentGraph extends
*/
public void testCreateGraph() {
em.getTransaction().begin();
+ assertFalse(em.contains(graph));
+ graph = em.find(PersistentGraph.class, graph.getId());
+ assertNotNull(graph);
People[] people = new People[SSN.length];
for (int i = 0; i < SSN.length; i++) {
People p = em.find(People.class, SSN[i]);
@@ -180,7 +181,7 @@ public class TestPersistentGraph extends
assertNotNull(c);
cities[i] = c;
}
- assertDataEquals(people, cities);
+ assertDataEquals(graph, people, cities);
em.getTransaction().rollback();
}
@@ -190,10 +191,11 @@ public class TestPersistentGraph extends
* correctly.
*/
public void testQueryRelation() {
- List<Relation> relations = em.createQuery("select r from Relation r", Relation.class).getResultList();
+ String jpql = "select r from PersistentRelation r";
+ List<PersistentRelation> relations = em.createQuery(jpql, PersistentRelation.class).getResultList();
for (Relation<?, ?> r : relations) {
- Vertex<?> source = r.getSource();
- Vertex<?> target = r.getTarget();
+ Object source = r.getSource();
+ Object target = r.getTarget();
if (source instanceof People) {
int i = indexOf((People) source);
if (target instanceof People) {
@@ -204,16 +206,16 @@ public class TestPersistentGraph extends
int j = indexOf((City) target);
assertEquals(i % CITY_NAMES.length, j);
assertTrue(r.getAttributes().isEmpty());
- } else {
- fail();
+ } else if (target != null){
+ fail("Unexpected relation " + r);
}
} else if (source instanceof City) {
int i = indexOf((City) source);
if (target instanceof City) {
int j = indexOf((City) target);
assertEquals(""+ATTR_DISTANCE_VALUE[i][j], r.getAttribute(ATTR_DISTANCE));
- } else {
- fail();
+ } else if (target != null) {
+ fail("Unexpected relation " + r);
}
}
}
@@ -224,8 +226,8 @@ public class TestPersistentGraph extends
*/
public void testQueryRelationOnSourceParameter() {
People p1 = em.find(People.class, SSN[0]);
- String jpql = "select r from Relation r where r.source = :node";
- List<Relation> result = em.createQuery(jpql, Relation.class)
+ String jpql = "select r from PersistentRelation r where r.source = :node";
+ List<PersistentRelation> result = em.createQuery(jpql, PersistentRelation.class)
.setParameter("node", p1)
.getResultList();
assertFalse("Result of [" + jpql + "] on source = " + p1 + " should not be empty", result.isEmpty());
@@ -235,8 +237,8 @@ public class TestPersistentGraph extends
* Tests that a relation can be queried predicated on its attribute key.
*/
public void testQueryRelationOnSingleAttributeKey() {
- String jpql = "select r from Relation r join r.attrs a where key(a) = :key";
- List<Relation> result = em.createQuery(jpql, Relation.class)
+ String jpql = "select r from PersistentRelation r join r.attrs a where key(a) = :key";
+ List<PersistentRelation> result = em.createQuery(jpql, PersistentRelation.class)
.setParameter("key", ATTR_EMOTION)
.getResultList();
@@ -248,9 +250,9 @@ public class TestPersistentGraph extends
* key-value pair.
*/
public void testQueryRelationOnSingleAttributeKeyValue() {
- String jpql = "select r from Relation r join r.attrs a where key(a) = :key and value(a) = :value";
+ String jpql = "select r from PersistentRelation r join r.attrs a where key(a) = :key and value(a) = :value";
String value = EMOTIONS[0][2].toString();
- List<Relation> result = em.createQuery(jpql, Relation.class)
+ List<PersistentRelation> result = em.createQuery(jpql, PersistentRelation.class)
.setParameter("key", ATTR_EMOTION)
.setParameter("value", value)
.getResultList();
@@ -265,10 +267,11 @@ public class TestPersistentGraph extends
* wrong result.
*/
public void testQueryRelationOnMultipleAttributeKeyValuePairs() {
- String jpql = "select r from Relation r join r.attrs a1 join r.attrs a2 "
- + "where key(a1) = :key1 and value(a1) = :value1 " + "and key(a2) = :key2 and value(a2) = :value2";
+ String jpql = "select r from PersistentRelation r join r.attrs a1 join r.attrs a2 "
+ + "where key(a1) = :key1 and value(a1) = :value1 "
+ + "and key(a2) = :key2 and value(a2) = :value2";
String value = EMOTIONS[0][2].toString();
- List<Relation> result = em.createQuery(jpql, Relation.class)
+ List<PersistentRelation> result = em.createQuery(jpql, PersistentRelation.class)
.setParameter("key1", ATTR_EMOTION)
.setParameter("value1", value)
.setParameter("key2", ATTR_SINCE)
@@ -279,10 +282,10 @@ public class TestPersistentGraph extends
+ ") and key-value=(" + ATTR_SINCE + "," + SINCE + ") should not be empty",
result.isEmpty());
- String wrongJPQL = "select r from Relation r join r.attrs a "
+ String wrongJPQL = "select r from PersistentRelation r join r.attrs a "
+ "where key(a) = :key1 and value(a) = :value1 "
+ "and key(a) = :key2 and value(a) = :value2";
- List<Relation> result2 = em.createQuery(wrongJPQL, Relation.class)
+ List<PersistentRelation> result2 = em.createQuery(wrongJPQL, PersistentRelation.class)
.setParameter("key1", ATTR_EMOTION)
.setParameter("value1", value)
.setParameter("key2", ATTR_SINCE)
@@ -297,8 +300,8 @@ public class TestPersistentGraph extends
public void testAddRemoveAttribute() {
em.getTransaction().begin();
People p1 = em.find(People.class, SSN[0]);
- String jpql = "select r from Relation r where r.source = :node";
- List<Relation> r = em.createQuery(jpql, Relation.class)
+ String jpql = "select r from PersistentRelation r where r.source = :node";
+ List<PersistentRelation> r = em.createQuery(jpql, PersistentRelation.class)
.setHint(QueryHints.HINT_IGNORE_PREPARED_QUERY, true)
.setParameter("node", p1)
.getResultList();
@@ -308,8 +311,8 @@ public class TestPersistentGraph extends
em.clear();
em.getTransaction().begin();
- jpql = "select r from Relation r join r.attrs a where key(a) = :key";
- Relation newR = em.createQuery(jpql, Relation.class)
+ jpql = "select r from PersistentRelation r join r.attrs a where key(a) = :key";
+ Relation newR = em.createQuery(jpql, PersistentRelation.class)
.setParameter("key", "new-key")
.getSingleResult();
assertNotNull(newR);
@@ -318,9 +321,9 @@ public class TestPersistentGraph extends
em.getTransaction().commit();
em.getTransaction().begin();
- jpql = "select r from Relation r join r.attrs a where key(a) = :key";
+ jpql = "select r from PersistentRelation r join r.attrs a where key(a) = :key";
try {
- newR = em.createQuery(jpql, Relation.class)
+ newR = em.createQuery(jpql, PersistentRelation.class)
.setParameter("key", "new-key")
.getSingleResult();
fail(jpql + " with new-key expected no result");
@@ -339,15 +342,15 @@ public class TestPersistentGraph extends
* Creates a typical graph of People and Cities. The tests are sensitive to
* the actual values and relations set in in this method.
*/
- void createData() {
- if (isPopulated())
- return;
+ PersistentGraph<Object> createData() {
+ PersistentGraph<Object> graph = new RelationGraph<Object>();
+
em.getTransaction().begin();
People[] people = new People[SSN.length];
for (int i = 0; i < SSN.length; i++) {
People p = new People();
- em.persist(p);
+ graph.add(p);
p.setSsn(SSN[i]);
p.setName(PERSON_NAMES[i]);
people[i] = p;
@@ -355,14 +358,15 @@ public class TestPersistentGraph extends
City[] cities = new City[CITY_NAMES.length];
for (int i = 0; i < CITY_NAMES.length; i++) {
City c = new City();
- em.persist(c);
+ graph.add(c);
c.setName(CITY_NAMES[i]);
cities[i] = c;
}
for (int i = 0; i < people.length; i++) {
for (int j = 0; j < people.length; j++) {
if (EMOTIONS[i][j] != null) {
- Relation<People, People> r = people[i].link(people[j]).addAttribute(ATTR_EMOTION, EMOTIONS[i][j]);
+ Relation<People, People> r = graph.link(people[i], people[j])
+ .addAttribute(ATTR_EMOTION, EMOTIONS[i][j]);
if (i == 0 && j == 2) {
r.addAttribute(ATTR_SINCE, SINCE);
}
@@ -371,18 +375,20 @@ public class TestPersistentGraph extends
}
for (int i = 0; i < cities.length; i++) {
for (int j = 0; j < cities.length; j++) {
- cities[i].link(cities[j]).addAttribute(ATTR_DISTANCE, ATTR_DISTANCE_VALUE[i][j]);
+ graph.link(cities[i], cities[j]).addAttribute(ATTR_DISTANCE, ATTR_DISTANCE_VALUE[i][j]);
}
}
for (int i = 0; i < people.length; i++) {
- people[i].link(cities[i % CITY_NAMES.length]);
+ graph.link(people[i], cities[i % CITY_NAMES.length]);
}
-
+ em.persist(graph);
em.getTransaction().commit();
+
+ return graph;
}
- void assertDataEquals(People[] people, City[] cities) {
+ void assertDataEquals(Graph<Object> graph, People[] people, City[] cities) {
assertEquals(SSN.length, people.length);
assertEquals(CITY_NAMES.length, cities.length);
@@ -399,7 +405,7 @@ public class TestPersistentGraph extends
People p1 = people[i];
for (int j = 0; j < people.length; j++) {
People p2 = people[j];
- Relation<People, People> r = p1.getRelationTo(p2);
+ Relation<People, People> r = graph.getRelation(p1,p2);
if (EMOTIONS[i][j] != null) {
assertNotNull(r);
assertEquals(EMOTIONS[i][j].toString(), r.getAttribute(ATTR_EMOTION));
@@ -412,7 +418,7 @@ public class TestPersistentGraph extends
City c1 = cities[i];
for (int j = 0; j < cities.length; j++) {
City c2 = cities[j];
- Relation<City, City> r12 = c1.getRelationTo(c2);
+ Relation<City, City> r12 = graph.getRelation(c1,c2);
assertNotNull(r12);
assertEquals(""+ATTR_DISTANCE_VALUE[i][j], r12.getAttribute(ATTR_DISTANCE));
}
@@ -422,7 +428,7 @@ public class TestPersistentGraph extends
People p = people[i];
for (int j = 0; j < cities.length; j++) {
City c = cities[j];
- Relation<People, City> r = p.getRelationTo(c);
+ Relation<People, City> r = graph.getRelation(p,c);
if (i % CITY_NAMES.length == j) {
assertNotNull(r);
} else {