This is an automated email from the ASF dual-hosted git repository.

ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git


The following commit(s) were added to refs/heads/master by this push:
     new 4c6c726b1 CAY-2830 Cleanup DataContext  - extract couple utility 
classes  - more comment cleanup
4c6c726b1 is described below

commit 4c6c726b17c8ede1760282d83891f515750402a2
Author: stariy95 <stari...@gmail.com>
AuthorDate: Wed Dec 6 12:39:33 2023 +0400

    CAY-2830 Cleanup DataContext
     - extract couple utility classes
     - more comment cleanup
---
 .../access/CollectingNamePropertyVisitor.java      |  60 ++++++
 .../org/apache/cayenne/access/DataContext.java     | 228 ++------------------
 .../cayenne/access/DataContextObjectCreator.java   | 229 +++++++++++++++++++++
 3 files changed, 302 insertions(+), 215 deletions(-)

diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/CollectingNamePropertyVisitor.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/CollectingNamePropertyVisitor.java
new file mode 100644
index 000000000..8137fe774
--- /dev/null
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/CollectingNamePropertyVisitor.java
@@ -0,0 +1,60 @@
+/*****************************************************************
+ *   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
+ *
+ *    https://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.cayenne.access;
+
+import org.apache.cayenne.reflect.AttributeProperty;
+import org.apache.cayenne.reflect.ClassDescriptor;
+import org.apache.cayenne.reflect.PropertyVisitor;
+import org.apache.cayenne.reflect.ToManyProperty;
+import org.apache.cayenne.reflect.ToOneProperty;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class CollectingNamePropertyVisitor implements PropertyVisitor {
+    private final List<String> properties;
+
+    CollectingNamePropertyVisitor() {
+        this.properties = new ArrayList<>();
+    }
+
+    @Override
+    public boolean visitAttribute(final AttributeProperty property) {
+        properties.add(property.getName());
+        return true;
+    }
+
+    @Override
+    public boolean visitToOne(final ToOneProperty property) {
+        properties.add(property.getName());
+        return true;
+    }
+
+    @Override
+    public boolean visitToMany(final ToManyProperty property) {
+        properties.add(property.getName());
+        return true;
+    }
+
+    List<String> allProperties(ClassDescriptor classDescriptor) {
+        classDescriptor.visitProperties(this);
+        return properties;
+    }
+}
diff --git a/cayenne/src/main/java/org/apache/cayenne/access/DataContext.java 
b/cayenne/src/main/java/org/apache/cayenne/access/DataContext.java
index cb57e0f9e..4faf2ef52 100644
--- a/cayenne/src/main/java/org/apache/cayenne/access/DataContext.java
+++ b/cayenne/src/main/java/org/apache/cayenne/access/DataContext.java
@@ -49,23 +49,16 @@ import org.apache.cayenne.cache.NestedQueryCache;
 import org.apache.cayenne.cache.QueryCache;
 import org.apache.cayenne.di.Injector;
 import org.apache.cayenne.event.EventManager;
-import org.apache.cayenne.exp.ValueInjector;
-import org.apache.cayenne.graph.ArcId;
 import org.apache.cayenne.graph.ChildDiffLoader;
 import org.apache.cayenne.graph.CompoundDiff;
 import org.apache.cayenne.graph.GraphDiff;
 import org.apache.cayenne.graph.GraphEvent;
 import org.apache.cayenne.graph.GraphManager;
 import org.apache.cayenne.map.EntityResolver;
-import org.apache.cayenne.map.LifecycleEvent;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.query.*;
-import org.apache.cayenne.reflect.AttributeProperty;
 import org.apache.cayenne.reflect.ClassDescriptor;
 import org.apache.cayenne.reflect.PropertyDescriptor;
-import org.apache.cayenne.reflect.PropertyVisitor;
-import org.apache.cayenne.reflect.ToManyProperty;
-import org.apache.cayenne.reflect.ToOneProperty;
 import org.apache.cayenne.runtime.CayenneRuntime;
 import org.apache.cayenne.tx.TransactionFactory;
 import org.apache.cayenne.util.EventUtil;
@@ -152,6 +145,8 @@ public class DataContext implements ObjectContext {
 
     protected boolean validatingObjectsOnCommit = true;
 
+    protected final DataContextObjectCreator objectCreator;
+
     /**
      * Creates a new DataContext that is not attached to the Cayenne stack.
      */
@@ -167,6 +162,7 @@ public class DataContext implements ObjectContext {
     public DataContext(DataChannel channel, ObjectStore objectStore) {
 
         graphAction = new ObjectContextGraphAction(this);
+        objectCreator = new DataContextObjectCreator(this);
 
         // inject self as parent context
         if (objectStore != null) {
@@ -566,10 +562,8 @@ public class DataContext implements ObjectContext {
     @Override
     public void prepareForAccess(Persistent object, String property, boolean 
lazyFaulting) {
         if (object.getPersistenceState() == PersistenceState.HOLLOW) {
-
             ObjectId oid = object.getObjectId();
             List<?> objects = performQuery(new ObjectIdQuery(oid, false, 
ObjectIdQuery.CACHE));
-
             if (objects.size() == 0) {
                 throw new FaultFailureException(
                         "Error resolving fault, no matching row exists in the 
database for ObjectId: " + oid);
@@ -577,16 +571,7 @@ public class DataContext implements ObjectContext {
                 throw new FaultFailureException(
                         "Error resolving fault, more than one row exists in 
the database for ObjectId: " + oid);
             }
-
-            // 5/28/2013 - Commented out this block to allow for modifying 
objects in the postLoad callback
-            // sanity check...
-            // if (object.getPersistenceState() != PersistenceState.COMMITTED) 
{
-            //     String state = 
PersistenceState.persistenceStateName(object.getPersistenceState());
-            //     // andrus 4/13/2006, modified and deleted states are 
possible due to a race condition,
-            //     // should we handle them here?
-            //     throw new FaultFailureException("Error resolving fault for 
ObjectId: " + oid + " and state (" + state
-            //             + "). Possible cause - matching row is missing from 
the database.");
-            // }
+            // here once was a sanity check for the COMMITTED state, that was 
faulty due to the race condition
         }
 
         // resolve relationship fault
@@ -597,55 +582,13 @@ public class DataContext implements ObjectContext {
 
             // If we don't have a property descriptor, there's not much we can 
do.
             // Let the caller know that the specified property could not be 
found and list
-            // all of the properties that could be so the caller knows what 
can be used.
+            // all the properties that could be so the caller knows what can 
be used.
             if (propertyDescriptor == null) {
-                final StringBuilder errorMessage = new StringBuilder();
-
-                errorMessage.append(String.format("Property '%s' is not 
declared for entity '%s'.", property, object
-                        .getObjectId().getEntityName()));
-
-                errorMessage.append(" Declared properties are: ");
-
-                // Grab each of the declared properties.
-                final List<String> properties = new ArrayList<>();
-                classDescriptor.visitProperties(new PropertyVisitor() {
-                    @Override
-                    public boolean visitAttribute(final AttributeProperty 
property) {
-                        properties.add(property.getName());
-
-                        return true;
-                    }
-
-                    @Override
-                    public boolean visitToOne(final ToOneProperty property) {
-                        properties.add(property.getName());
-
-                        return true;
-                    }
-
-                    @Override
-                    public boolean visitToMany(final ToManyProperty property) {
-                        properties.add(property.getName());
-
-                        return true;
-                    }
-                });
-
-                // Now add the declared property names to the error message.
-                boolean first = true;
-                for (String declaredProperty : properties) {
-                    if (first) {
-                        errorMessage.append(String.format("'%s'", 
declaredProperty));
-
-                        first = false;
-                    } else {
-                        errorMessage.append(String.format(", '%s'", 
declaredProperty));
-                    }
-                }
-
-                errorMessage.append(".");
-
-                throw new CayenneRuntimeException(errorMessage.toString());
+                List<String> properties = new 
CollectingNamePropertyVisitor().allProperties(classDescriptor);
+                String errorMessage = String.format("Property '%s' is not 
declared for entity '%s'.",
+                        property, object.getObjectId().getEntityName()) +
+                        " Declared properties are: '" + String.join("', '", 
properties) + "'.";
+                throw new CayenneRuntimeException(errorMessage);
             }
 
             // this should trigger fault resolving
@@ -712,16 +655,7 @@ public class DataContext implements ObjectContext {
      */
     @Override
     public <T> T newObject(Class<T> persistentClass) {
-        if (persistentClass == null) {
-            throw new NullPointerException("Null 'persistentClass'");
-        }
-
-        ObjEntity entity = getEntityResolver().getObjEntity(persistentClass);
-        if (entity == null) {
-            throw new IllegalArgumentException("Class is not mapped with 
Cayenne: " + persistentClass.getName());
-        }
-
-        return (T) newObject(entity.getName());
+        return objectCreator.newObject(persistentClass);
     }
 
     /**
@@ -736,27 +670,7 @@ public class DataContext implements ObjectContext {
      * @since 3.0
      */
     public Persistent newObject(String entityName) {
-        ClassDescriptor descriptor = 
getEntityResolver().getClassDescriptor(entityName);
-        if (descriptor == null) {
-            throw new IllegalArgumentException("Invalid entity name: " + 
entityName);
-        }
-
-        Persistent object;
-        try {
-            object = (Persistent) descriptor.createObject();
-        } catch (Exception ex) {
-            throw new CayenneRuntimeException("Error instantiating object.", 
ex);
-        }
-
-        // this will initialize to-many lists
-        descriptor.injectValueHolders(object);
-
-        // NOTE: the order of initialization of persistence artifacts below is 
important - do not change it lightly
-        object.setObjectId(ObjectId.of(entityName));
-
-        injectInitialValue(object);
-
-        return object;
+        return objectCreator.newObject(entityName);
     }
 
     /**
@@ -771,123 +685,7 @@ public class DataContext implements ObjectContext {
      */
     @Override
     public void registerNewObject(Object object) {
-        if (object == null) {
-            throw new NullPointerException("Can't register null object.");
-        }
-
-        ObjEntity entity = getEntityResolver().getObjEntity((Persistent) 
object);
-        if (entity == null) {
-            throw new IllegalArgumentException("Can't find ObjEntity for 
Persistent class: "
-                    + object.getClass().getName() + ", class is likely not 
mapped.");
-        }
-
-        final Persistent persistent = (Persistent) object;
-
-        // sanity check - maybe already registered
-        if (persistent.getObjectId() != null) {
-            if (persistent.getObjectContext() == this) {
-                // already registered, just ignore
-                return;
-            } else if (persistent.getObjectContext() != null) {
-                throw new IllegalStateException("Persistent is already 
registered with another DataContext. "
-                        + "Try using 'localObjects()' instead.");
-            }
-        } else {
-            persistent.setObjectId(ObjectId.of(entity.getName()));
-        }
-
-        ClassDescriptor descriptor = 
getEntityResolver().getClassDescriptor(entity.getName());
-        if (descriptor == null) {
-            throw new IllegalArgumentException("Invalid entity name: " + 
entity.getName());
-        }
-
-        injectInitialValue(object);
-
-        // now we need to find all arc changes, inject missing value holders 
and
-        // pull in all transient connected objects
-
-        descriptor.visitProperties(new PropertyVisitor() {
-
-            public boolean visitToMany(ToManyProperty property) {
-                property.injectValueHolder(persistent);
-
-                if (!property.isFault(persistent)) {
-
-                    Object value = property.readProperty(persistent);
-                    @SuppressWarnings("unchecked")
-                    Collection<Map.Entry<?,?>> collection = (value instanceof 
Map)
-                            ? ((Map) value).entrySet()
-                            : (Collection<Map.Entry<?, ?>>) value;
-
-                    for (Object target : collection) {
-                        if (target instanceof Persistent) {
-                            Persistent targetDO = (Persistent) target;
-
-                            // make sure it is registered
-                            registerNewObject(targetDO);
-                            
getObjectStore().arcCreated(persistent.getObjectId(), targetDO.getObjectId(), 
new ArcId(property));
-                        }
-                    }
-                }
-                return true;
-            }
-
-            public boolean visitToOne(ToOneProperty property) {
-                Object target = property.readPropertyDirectly(persistent);
-
-                if (target instanceof Persistent) {
-
-                    Persistent targetDO = (Persistent) target;
-
-                    // make sure it is registered
-                    registerNewObject(targetDO);
-                    getObjectStore().arcCreated(persistent.getObjectId(), 
targetDO.getObjectId(), new ArcId(property));
-                }
-                return true;
-            }
-
-            public boolean visitAttribute(AttributeProperty property) {
-                return true;
-            }
-        });
-    }
-
-    /**
-     * If ObjEntity qualifier is set, asks it to inject initial value to an 
object.
-     * Also performs all Persistent initialization operations
-     */
-    protected void injectInitialValue(Object obj) {
-        // must follow this exact order of property initialization per CAY-653,
-        // i.e. have
-        // the id and the context in place BEFORE setPersistence is called
-
-        Persistent object = (Persistent) obj;
-
-        object.setObjectContext(this);
-        object.setPersistenceState(PersistenceState.NEW);
-
-        GraphManager graphManager = getGraphManager();
-        synchronized (graphManager) {
-            graphManager.registerNode(object.getObjectId(), object);
-            graphManager.nodeCreated(object.getObjectId());
-        }
-
-        ObjEntity entity;
-        try {
-            entity = getEntityResolver().getObjEntity(object.getClass());
-        } catch (CayenneRuntimeException ex) {
-            // ObjEntity cannot be fetched, ignored
-            entity = null;
-        }
-
-        if (entity != null) {
-            if (entity.getDeclaredQualifier() instanceof ValueInjector) {
-                ((ValueInjector) 
entity.getDeclaredQualifier()).injectValue(object);
-            }
-        }
-
-        // invoke callbacks
-        
getEntityResolver().getCallbackRegistry().performCallbacks(LifecycleEvent.POST_ADD,
 object);
+        objectCreator.registerNewObject(object);
     }
 
     /**
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/DataContextObjectCreator.java 
b/cayenne/src/main/java/org/apache/cayenne/access/DataContextObjectCreator.java
new file mode 100644
index 000000000..0c3ec5af6
--- /dev/null
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/DataContextObjectCreator.java
@@ -0,0 +1,229 @@
+/*****************************************************************
+ *   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
+ *
+ *    https://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.cayenne.access;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.PersistenceState;
+import org.apache.cayenne.Persistent;
+import org.apache.cayenne.exp.ValueInjector;
+import org.apache.cayenne.graph.ArcId;
+import org.apache.cayenne.graph.GraphManager;
+import org.apache.cayenne.map.LifecycleEvent;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.reflect.AttributeProperty;
+import org.apache.cayenne.reflect.ClassDescriptor;
+import org.apache.cayenne.reflect.PropertyVisitor;
+import org.apache.cayenne.reflect.ToManyProperty;
+import org.apache.cayenne.reflect.ToOneProperty;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * {@link DataContext} delegates creation and registration of new objects to 
this class
+ */
+class DataContextObjectCreator {
+
+    private final DataContext context;
+
+    DataContextObjectCreator(DataContext context) {
+        this.context = context;
+    }
+
+    /**
+     * Create new object for the given persistent class
+     *
+     * @param persistentClass to create object from
+     * @return a new persistent object
+     * @param <T> type of the object
+     * @see DataContext#newObject(Class)
+     */
+    <T> T newObject(Class<T> persistentClass) {
+        if (persistentClass == null) {
+            throw new NullPointerException("Null 'persistentClass'");
+        }
+
+        ObjEntity entity = 
context.getEntityResolver().getObjEntity(persistentClass);
+        if (entity == null) {
+            throw new IllegalArgumentException("Class is not mapped with 
Cayenne: " + persistentClass.getName());
+        }
+
+        @SuppressWarnings("unchecked")
+        T object = (T) newObject(entity.getName());
+        return object;
+    }
+
+    /**
+     * Create new object for the given entity name
+     * @param entityName name of the ObjEntity
+     * @return a new persistent object
+     * @see DataContext#newObject(String)
+     */
+    Persistent newObject(String entityName) {
+        ClassDescriptor descriptor = 
context.getEntityResolver().getClassDescriptor(entityName);
+        if (descriptor == null) {
+            throw new IllegalArgumentException("Invalid entity name: " + 
entityName);
+        }
+
+        Persistent object;
+        try {
+            object = (Persistent) descriptor.createObject();
+        } catch (Exception ex) {
+            throw new CayenneRuntimeException("Error instantiating object.", 
ex);
+        }
+
+        // this will initialize to-many lists
+        descriptor.injectValueHolders(object);
+
+        // NOTE: the order of initialization of persistence artifacts below is 
important - do not change it lightly
+        object.setObjectId(ObjectId.of(entityName));
+
+        injectInitialValue(object);
+
+        return object;
+    }
+
+    /**
+     * Register new object created outside the context
+     * @param object to register
+     * @see DataContext#registerNewObject(Object)
+     */
+    void registerNewObject(Object object) {
+        if (object == null) {
+            throw new NullPointerException("Can't register null object.");
+        }
+
+        ObjEntity entity = 
context.getEntityResolver().getObjEntity((Persistent) object);
+        if (entity == null) {
+            throw new IllegalArgumentException("Can't find ObjEntity for 
Persistent class: "
+                    + object.getClass().getName() + ", class is likely not 
mapped.");
+        }
+
+        final Persistent persistent = (Persistent) object;
+
+        // sanity check - maybe already registered
+        if (persistent.getObjectId() != null) {
+            if (persistent.getObjectContext() == context) {
+                // already registered, just ignore
+                return;
+            } else if (persistent.getObjectContext() != null) {
+                throw new IllegalStateException("Persistent is already 
registered with another DataContext. "
+                        + "Try using 'localObjects()' instead.");
+            }
+        } else {
+            persistent.setObjectId(ObjectId.of(entity.getName()));
+        }
+
+        ClassDescriptor descriptor = 
context.getEntityResolver().getClassDescriptor(entity.getName());
+        if (descriptor == null) {
+            throw new IllegalArgumentException("Invalid entity name: " + 
entity.getName());
+        }
+
+        injectInitialValue(object);
+
+        // now we need to find all arc changes, inject missing value holders 
and
+        // pull in all transient connected objects
+
+        descriptor.visitProperties(new PropertyVisitor() {
+
+            public boolean visitToMany(ToManyProperty property) {
+                property.injectValueHolder(persistent);
+
+                if (!property.isFault(persistent)) {
+
+                    Object value = property.readProperty(persistent);
+                    @SuppressWarnings({"unchecked", "rawtypes"})
+                    Collection<Map.Entry<?,?>> collection = (value instanceof 
Map)
+                            ? ((Map) value).entrySet()
+                            : (Collection<Map.Entry<?, ?>>) value;
+
+                    for (Object target : collection) {
+                        if (target instanceof Persistent) {
+                            Persistent targetDO = (Persistent) target;
+
+                            // make sure it is registered
+                            registerNewObject(targetDO);
+                            
context.getObjectStore().arcCreated(persistent.getObjectId(), 
targetDO.getObjectId(), new ArcId(property));
+                        }
+                    }
+                }
+                return true;
+            }
+
+            public boolean visitToOne(ToOneProperty property) {
+                Object target = property.readPropertyDirectly(persistent);
+
+                if (target instanceof Persistent) {
+
+                    Persistent targetDO = (Persistent) target;
+
+                    // make sure it is registered
+                    registerNewObject(targetDO);
+                    
context.getObjectStore().arcCreated(persistent.getObjectId(), 
targetDO.getObjectId(), new ArcId(property));
+                }
+                return true;
+            }
+
+            public boolean visitAttribute(AttributeProperty property) {
+                return true;
+            }
+        });
+    }
+
+    /**
+     * If ObjEntity qualifier is set, asks it to inject initial value to an 
object.
+     * Also performs all Persistent initialization operations
+     */
+    @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
+    protected void injectInitialValue(Object obj) {
+        // must follow this exact order of property initialization per CAY-653,
+        // i.e. have the id and the context in place BEFORE setPersistence is 
called
+
+        Persistent object = (Persistent) obj;
+
+        object.setObjectContext(context);
+        object.setPersistenceState(PersistenceState.NEW);
+
+        GraphManager graphManager = context.getGraphManager();
+        synchronized (graphManager) {
+            graphManager.registerNode(object.getObjectId(), object);
+            graphManager.nodeCreated(object.getObjectId());
+        }
+
+        ObjEntity entity;
+        try {
+            entity = 
context.getEntityResolver().getObjEntity(object.getClass());
+        } catch (CayenneRuntimeException ex) {
+            // ObjEntity cannot be fetched, ignored
+            entity = null;
+        }
+
+        if (entity != null) {
+            if (entity.getDeclaredQualifier() instanceof ValueInjector) {
+                ((ValueInjector) 
entity.getDeclaredQualifier()).injectValue(object);
+            }
+        }
+
+        // invoke callbacks
+        context.getEntityResolver()
+                
.getCallbackRegistry().performCallbacks(LifecycleEvent.POST_ADD, object);
+    }
+}

Reply via email to