| /* |
| * Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // ailitchev - Bug 244124 - Added AttributeGroup base class for nesting |
| // 09 Jan 2013-2.5 Gordon Yorke |
| // - 397772: JPA 2.1 Entity Graph Support |
| package org.eclipse.persistence.queries; |
| |
| import java.io.Serializable; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.IdentityHashMap; |
| import java.util.Map; |
| |
| import org.eclipse.persistence.core.queries.CoreAttributeGroup; |
| import org.eclipse.persistence.descriptors.ClassDescriptor; |
| import org.eclipse.persistence.internal.queries.AttributeItem; |
| import org.eclipse.persistence.sessions.CopyGroup; |
| |
| /** |
| * <b>Purpose</b>: An AttributeGroup represents a set of mappings and nested |
| * AttributeGroups for relationship mappings for an entity type. |
| * <b>Responsibilities</b>: |
| * <ul> |
| * <li>Defines which attributes should be fetched from the database within a |
| * {@link FetchGroup}. |
| * <li>Define which relationship attributes should be populated in a resulting |
| * entity graph within a {@link LoadGroup} |
| * <li>Define which attributes should be copied within a {@link CopyGroup} |
| * </ul> |
| * <p> |
| * To reference nested attributes a dot ('.') notation is used to reference |
| * related attributes. All attribute names provided are assumed to be correct |
| * until processed against the mappings during usage of the group. |
| * |
| * @see FetchGroup |
| * @see LoadGroup |
| * @see CopyGroup |
| * |
| * @author ailitchev |
| * @since EclipseLink 2.1 |
| */ |
| public class AttributeGroup extends CoreAttributeGroup<AttributeItem, ClassDescriptor> implements Serializable, Cloneable { |
| |
| public AttributeGroup(String name) { |
| this.name = name; |
| } |
| |
| /** |
| * INTERNAL: |
| * This constructer is to only be used by EclipseLink internally |
| */ |
| public AttributeGroup(String name, Class type, boolean isValidated) { |
| this(name); |
| this.type = type; |
| this.isValidated = isValidated; |
| |
| } |
| |
| /* |
| * INTERNAL: |
| * Used to create an attribute with a name of the class type. |
| */ |
| public AttributeGroup(String name, String type, boolean isValidated) { |
| this(name); |
| this.typeName = type; |
| this.isValidated = isValidated; |
| |
| } |
| |
| public AttributeGroup() { |
| this(""); |
| } |
| |
| /** |
| * Add a basic attribute or nested attribute with each String representing |
| * an attribute on the path to what needs to be included in the |
| * AttributeGroup. |
| * <p> |
| * Example: <code> |
| * group.addAttribute("firstName", group1);<br> |
| * group.addAttribute("manager.address", group2); |
| * </code> |
| * |
| * Note that existing group corresponding to attributeNameOrPath |
| * will be overridden with the passed group. |
| * |
| * @param attributeNameOrPath |
| * A simple attribute, array or attributes forming a path |
| * @param group - an AttributeGroup to be added. |
| */ |
| public void addAttribute(String attributeNameOrPath, AttributeGroup group) { |
| super.addAttribute(attributeNameOrPath, group); |
| } |
| |
| /** |
| * Returns AttributeGroup corresponding to the passed (possibly nested) |
| * attribute. |
| */ |
| @Override |
| public AttributeGroup getGroup(String attributeNameOrPath) { |
| return (AttributeGroup)super.getGroup(attributeNameOrPath); |
| } |
| |
| /** |
| * Return true if this AttributeGroup is a super-set of the passed in |
| * AttributeGroup. |
| */ |
| public boolean isSupersetOf(AttributeGroup anotherGroup) { |
| return super.isSupersetOf(anotherGroup); |
| } |
| |
| /** |
| * INTERNAL: |
| * Lookup the {@link AttributeItem}for the provided attribute name or path. |
| * |
| * @return item or null |
| * @throws IllegalArgumentException if name is not valid attribute name or path |
| */ |
| @Override |
| public AttributeItem getItem(String attributeNameOrPath) { |
| return super.getItem(attributeNameOrPath); |
| } |
| |
| /** |
| * Subclass may create different types. |
| */ |
| protected AttributeItem newItem(AttributeGroup group, String attrName) { |
| return new AttributeItem(group, attrName); |
| } |
| |
| @Override |
| public AttributeGroup findGroup(ClassDescriptor type){ |
| return (AttributeGroup)super.findGroup(type); |
| } |
| |
| /** |
| * Convert the group to a FetchGroup for usage with queries. |
| */ |
| public FetchGroup toFetchGroup() { |
| if (isFetchGroup()) { |
| return (FetchGroup) this; |
| } |
| return toFetchGroup(new HashMap<AttributeGroup, FetchGroup>()); |
| } |
| |
| /** |
| * INTERNAL: |
| * This method is used internally when converting to a copy group. |
| */ |
| |
| public FetchGroup toFetchGroup(Map<AttributeGroup, FetchGroup> cloneMap){ |
| FetchGroup clone = cloneMap.get(this); |
| if (clone != null) { |
| return clone; |
| } |
| clone = new FetchGroup(this.name); |
| |
| clone.type = this.type; |
| clone.typeName = this.typeName; |
| clone.isValidated = this.isValidated; |
| cloneMap.put(this,clone); |
| if (this.superClassGroup != null){ |
| clone.superClassGroup = ((AttributeGroup)this.superClassGroup).toFetchGroup(cloneMap); |
| } |
| if (this.allsubclasses != null){ |
| for (CoreAttributeGroup group : this.allsubclasses.values()){ |
| clone.getSubClassGroups().put(group.getType(), ((AttributeGroup)group).toFetchGroup(cloneMap)); |
| } |
| } |
| if (this.subClasses != null){ |
| clone.subClasses = new HashSet<>(); |
| for (CoreAttributeGroup group : this.subClasses){ |
| clone.subClasses.add(((AttributeGroup)group).toFetchGroup(cloneMap)); |
| } |
| } |
| // all attributes and nested groups should be cloned, too |
| clone.items = null; |
| if (hasItems()) { |
| clone.items = new HashMap<>(); |
| for (AttributeItem item : this.items.values()){ |
| clone.items.put(item.getAttributeName(), item.toFetchGroup(cloneMap, clone)); |
| } |
| } |
| return clone; |
| } |
| |
| /** |
| * INTERNAL: |
| * This method is used internally when converting to a copy group. |
| */ |
| |
| @Override |
| public boolean isCopyGroup() { |
| return false; |
| } |
| |
| /** |
| * Convert the group to a CopyGroup for usage with the copy() API. |
| */ |
| public CopyGroup toCopyGroup() { |
| if (isCopyGroup()) { |
| return (CopyGroup) this; |
| } |
| Map<AttributeGroup, CopyGroup> cloneMap = new IdentityHashMap<>(); |
| return toCopyGroup(cloneMap, new HashMap<>()); |
| } |
| |
| /** |
| * INTERNAL: |
| * This method is used internally when converting to a copy group. |
| */ |
| |
| public CopyGroup toCopyGroup(Map<AttributeGroup, CopyGroup> cloneMap, Map copies){ |
| CopyGroup clone = cloneMap.get(this); |
| if (clone != null) { |
| return clone; |
| } |
| clone = new CopyGroup(this.name); |
| clone.cascadeTree(); |
| clone.setCopies(copies); |
| |
| clone.type = this.type; |
| clone.typeName = this.typeName; |
| clone.isValidated = this.isValidated; |
| cloneMap.put(this,clone); |
| |
| if (this.allsubclasses != null){ |
| for (CoreAttributeGroup group : this.allsubclasses.values()){ |
| clone.getSubClassGroups().put(group.getType(), ((AttributeGroup)group).toCopyGroup(cloneMap, copies)); |
| } |
| } |
| if (this.superClassGroup != null){ |
| clone.superClassGroup = ((AttributeGroup)this.superClassGroup).toCopyGroup(cloneMap, copies); |
| } |
| if (this.subClasses != null){ |
| clone.subClasses = new HashSet<>(); |
| for (CoreAttributeGroup group : this.subClasses){ |
| clone.subClasses.add(((AttributeGroup)group).toCopyGroup(cloneMap, copies)); |
| } |
| } |
| // all attributes and nested groups should be cloned, too |
| clone.items = null; |
| if (hasItems()) { |
| clone.items = new HashMap<>(); |
| for (AttributeItem item : this.items.values()){ |
| clone.items.put(item.getAttributeName(), item.toCopyGroup(cloneMap, clone, copies)); |
| } |
| } |
| return clone; |
| } |
| |
| |
| @Override |
| public boolean isLoadGroup() { |
| return false; |
| } |
| |
| /** |
| * Convert the group to a LoadGroup for usage with queries. |
| */ |
| public LoadGroup toLoadGroup() { |
| if (this.isLoadGroup()) { |
| return (LoadGroup) this; |
| } |
| return toLoadGroup(new HashMap<AttributeGroup, LoadGroup>(), false); |
| } |
| |
| public LoadGroup toLoadGroup(Map<AttributeGroup, LoadGroup> cloneMap, boolean loadOnly){ |
| LoadGroup clone = cloneMap.get(this); |
| if (clone != null) { |
| return clone; |
| } |
| clone = new LoadGroup(this.name); |
| |
| clone.type = this.type; |
| clone.typeName = this.typeName; |
| clone.isValidated = this.isValidated; |
| cloneMap.put(this,clone); |
| if (this.allsubclasses != null){ |
| for (CoreAttributeGroup group : this.allsubclasses.values()){ |
| clone.getSubClassGroups().put(group.getType(), ((AttributeGroup)group).toLoadGroup(cloneMap, loadOnly)); |
| } |
| } |
| if (this.superClassGroup != null){ |
| clone.superClassGroup = ((AttributeGroup)this.superClassGroup).toLoadGroup(cloneMap, loadOnly); |
| } |
| if (this.subClasses != null){ |
| clone.subClasses = new HashSet<>(); |
| for (CoreAttributeGroup group : this.subClasses){ |
| clone.subClasses.add(((AttributeGroup)group).toLoadGroup(cloneMap, loadOnly)); |
| } |
| } |
| // all attributes and nested groups should be cloned, too |
| clone.items = null; |
| if (hasItems()) { |
| clone.items = new HashMap<>(); |
| for (AttributeItem item : this.items.values()){ |
| clone.items.put(item.getAttributeName(), item.toLoadGroup(cloneMap, clone, loadOnly)); |
| } |
| } |
| return clone; |
| } |
| |
| @Override |
| public AttributeGroup clone() { |
| return (AttributeGroup)super.clone(); |
| } |
| |
| /** |
| * INTERNAL: |
| * Only LoadGroups allow concurrency. |
| */ |
| @Override |
| public boolean isConcurrent() { |
| return false; |
| } |
| /** |
| * Subclass may create different types. |
| */ |
| @Override |
| protected AttributeItem newItem(CoreAttributeGroup group, String attrName) { |
| return new AttributeItem((AttributeGroup)group, attrName); |
| } |
| |
| /** |
| * Subclass may create different types. |
| */ |
| @Override |
| protected AttributeGroup newGroup(String name, CoreAttributeGroup parent) { |
| return new AttributeGroup(name); |
| } |
| |
| |
| } |