Return-Path: Delivered-To: apmail-openjpa-commits-archive@www.apache.org Received: (qmail 4005 invoked from network); 16 Jun 2010 23:23:20 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 16 Jun 2010 23:23:20 -0000 Received: (qmail 92012 invoked by uid 500); 16 Jun 2010 23:23:20 -0000 Delivered-To: apmail-openjpa-commits-archive@openjpa.apache.org Received: (qmail 91973 invoked by uid 500); 16 Jun 2010 23:23:20 -0000 Mailing-List: contact commits-help@openjpa.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@openjpa.apache.org Delivered-To: mailing list commits@openjpa.apache.org Received: (qmail 91966 invoked by uid 99); 16 Jun 2010 23:23:20 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 16 Jun 2010 23:23:20 +0000 X-ASF-Spam-Status: No, hits=-1539.1 required=10.0 tests=ALL_TRUSTED,AWL X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 16 Jun 2010 23:23:17 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 22B02238897A; Wed, 16 Jun 2010 23:22:32 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r955425 - /openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/graph/ Date: Wed, 16 Jun 2010 23:22:31 -0000 To: commits@openjpa.apache.org From: ppoddar@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100616232232.22B02238897A@eris.apache.org> 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 type of element of the graph. + */ +public abstract class AbstractGraph extends AbstractSet implements Graph { + /** + * 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> rs = getRelationsTo(node); + for (Relation 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 { +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}. + *
+ * 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 Type of element of the graph + * + * + * @author Pinaki Poddar + * + */ +public interface Graph extends Set { + /** + * 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 generic type of source node + * @param generic type of target node + * + * @return a relation + */ + public Relation 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 generic type of source node + * @param generic type of target node + * + * @return the existing relation, if any, that had been broken. null otherwise. + */ + public Relation 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 generic type of source node + * @param generic type of target node + * + * @return a relation between the nodes, if exists. null otherwise. + */ + public Relation 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 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 getSources(E target); + + /** + * Gets all the relations originating from the given source. + * @param + * @param source + * @return + */ + public Set> getRelationsFrom(V source); + + /** + * Gets all the relations terminating on the given target. + * @param + * @param target + * @return + */ + public Set> 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{ +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}. + *
+ * 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 not represent + * container instances such as {@link java.util.Set} or {@link java.util.List} as first class 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. + *
+ * Persistent Graph defines a auto-generated persistent identity. + * + * @author Pinaki Poddar + * + * @param type of element. + */ +@SuppressWarnings("serial") +@MappedSuperclass +public abstract class PersistentGraph extends AbstractGraph 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. *
* A relation is *
    - *
  1. generic because the vertices it links are generically typed. - *
  2. directed because it distinguishes the two end points as source and target. + *
  3. generic because Relation type is parameterized with the type of vertices it links. + *
  4. directed because it distinguishes the two vertices as source and target. *
  5. attributed because any arbitrary name-value pair can be associated with a relation. *
+ * A relation is made persistence capable by annotating its generic source and target as persistent entity. + * A relation is also a first-class entity having its own persistent identifier. + *
* 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. + *
* @param the type of source vertex linked by this relation. * @param the type of target vertex linked by this relation. * @@ -49,7 +52,7 @@ import javax.persistence.OneToOne; */ @SuppressWarnings("serial") @Entity -public class Relation implements Serializable { +public class PersistentRelation implements Relation, Serializable { /** * Relation is a first class object with its own identifier. */ @@ -60,14 +63,16 @@ public class Relation implements /** * A Relation must have a non-null vertex as source. */ - @OneToOne(optional=false) - private Vertex 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 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 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 s, Vertex 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 implements /** * Gets the immutable source vertex. - */ - public Vertex getSource() { + */ + public V1 getSource() { return source; } /** * Gets the immutable target vertex. - */ - public Vertex getTarget() { + */ + public V2 getTarget() { return target; } @@ -181,4 +186,8 @@ public class Relation 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. *
* A relation is *
    - *
  1. generic because the vertices it links are generically typed. - *
  2. directed because it distinguishes the two end points as source and target. - *
  3. attributed because any arbitrary name-value pair can be associated with a relation. + *
  4. generic because Relation type is parameterized with the type of vertices it links. + *
  5. directed because it distinguishes the two vertices as source and target. + *
  6. attributed because any arbitrary key-value pair can be associated with a relation. *
+ *
* 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. + *
* @param the type of source vertex linked by this relation. * @param the type of target vertex linked by this relation. * * @author Pinaki Poddar * */ -@SuppressWarnings("serial") -@Entity -public class Relation implements Serializable { +public interface Relation { /** - * 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 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 target; + public V1 getSource(); /** - * The properties of a Relation is a set of key-value pairs and is declared as - * java.util.Properties. - *
- * Declaring the key-value pairs as java.util.Properties makes OpenJPA - * assume that both key and value will be stored in database as String. - * This is not strictly correct because java.util.Properties - * declares its key and value as java.lang.Object. 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. - *
- * Another possibility to express key-value pair as - *
- * Map attrs; - *
- * 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. - *
- * The third alternative is a Map where keys are String and values are Object - *
- * Map attrs; - * 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 s, Vertex 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 fluent method-chaining */ - public long getId() { - return id; - } - - /** - * Gets the immutable source vertex. - */ - public Vertex getSource() { - return source; - } - - /** - * Gets the immutable target vertex. - */ - public Vertex getTarget() { - return target; - } + public Relation 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 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 fluent method chaining. + */ + public Relation removeAttribute(String key); + + /** + * Gets the key-value pairs associated with this relation. */ - public Relation 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 extends PersistentGraph { + @OneToMany(cascade={CascadeType.PERSIST,CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH}) + private Set> relations = new HashSet>(); + + /* + * 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 Relation 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 r = getRelation(source, target); + if (r == null) { + r = new PersistentRelation(source, target); + relations.add((PersistentRelation) r); + } + return r; + + } + + /* + * Delinks the given vertices, if they are currently connected. + * + * + * @see org.apache.openjpa.persistence.graph.Graph#delink(V1, V2) + */ + public Relation delink(V1 source, V2 target) { + Relation 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 Relation getRelation(V1 source, V2 target) { + for (Relation r : relations) { + if (r.getSource().equals(source) && r.getTarget() != null && r.getTarget().equals(target)) { + return (Relation)r; + } + } + return null; + } + + /** + * Iterator over the nodes of this graph. + */ + public Iterator iterator() { + return getNodes().iterator(); + } + + public int size() { + return 0; + } + + @Override + public Set> getRelationsFrom(V source) { + Set> rs = new HashSet>(); + for (Relation r : relations) { + if (r.getSource().equals(source) && r.getTarget() != null) + rs.add((Relation)r); + } + return rs; + } + + @Override + public Set> getRelationsTo(V target) { + Set> rs = new HashSet>(); + for (Relation r : relations) { + if (r.getTarget() != null && r.getTarget().equals(target)) + rs.add((Relation)r); + } + return rs; + } + + @Override + public Set getSources(Object target) { + Set sources = new HashSet(); + for (Relation r : relations) { + if (r.getTarget() != null && r.getTarget().equals(target)) + sources.add(r.getSource()); + } + return sources; + } + + @Override + public Set getTargets(Object source) { + Set targets = new HashSet(); + for (Relation r : relations) { + if (r.getSource().equals(source) && r.getTarget() != null) + targets.add(r.getTarget()); + } + return targets; + } + + public Set 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,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 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 strategy, Class 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 relations = em.createQuery("select r from Relation r", Relation.class).getResultList(); + String jpql = "select r from PersistentRelation r"; + List 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 result = em.createQuery(jpql, Relation.class) + String jpql = "select r from PersistentRelation r where r.source = :node"; + List 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 result = em.createQuery(jpql, Relation.class) + String jpql = "select r from PersistentRelation r join r.attrs a where key(a) = :key"; + List 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 result = em.createQuery(jpql, Relation.class) + List 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 result = em.createQuery(jpql, Relation.class) + List 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 result2 = em.createQuery(wrongJPQL, Relation.class) + List 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 r = em.createQuery(jpql, Relation.class) + String jpql = "select r from PersistentRelation r where r.source = :node"; + List 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 createData() { + PersistentGraph graph = new RelationGraph(); + 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 r = people[i].link(people[j]).addAttribute(ATTR_EMOTION, EMOTIONS[i][j]); + Relation 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 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 r = p1.getRelationTo(p2); + Relation 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 r12 = c1.getRelationTo(c2); + Relation 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 r = p.getRelationTo(c); + Relation r = graph.getRelation(p,c); if (i % CITY_NAMES.length == j) { assertNotNull(r); } else {