blob: 7fdde4dbd33d48e9136c888629af261221044854 [file] [log] [blame]
/*
* 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:
// Matt MacIvor - 2.5 - initial implementation
package org.eclipse.persistence.core.queries;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.persistence.internal.core.helper.CoreClassConstants;
import org.eclipse.persistence.internal.localization.ExceptionLocalization;
/**
* INTERNAL
* <b>Purpose</b>: Generic superclass for AttributeItem.
*
* @author matt macivor
* @since EclipseLink 2.5
*/
public class CoreAttributeItem<ATTRIBUTE_GROUP extends CoreAttributeGroup> implements Serializable, Cloneable {
protected String attributeName;
protected ATTRIBUTE_GROUP parent;
protected ATTRIBUTE_GROUP group;
protected ATTRIBUTE_GROUP keyGroup;
protected Map<Object, ATTRIBUTE_GROUP> subGroups;
protected Map<Object, ATTRIBUTE_GROUP> keyGroups;
// private transient DatabaseMapping mapping;
protected CoreAttributeItem() {
}
public CoreAttributeItem(ATTRIBUTE_GROUP parent, String attributeName) {
this.parent = parent;
this.attributeName = attributeName;
}
/**
* INTERNAL:
* Adds the list of groups as to the item
*/
public void addGroups(Collection<ATTRIBUTE_GROUP> groups) {
for (ATTRIBUTE_GROUP group : groups){
addSubGroup(group);
}
}
public void addKeyGroup(ATTRIBUTE_GROUP keyGroup) {
if (keyGroup != null){
if (this.keyGroups == null){
this.keyGroups = new HashMap<>();
}
if (this.keyGroup == null){
this.keyGroup = keyGroup;
}
Object type = keyGroup.getType();
if (type == null){
type = keyGroup.getTypeName();
}
if (type == null){
type = CoreClassConstants.OBJECT;
if (this.keyGroups.containsKey(type)){
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("only_one_root_subgraph"));
}
}
this.keyGroups.put(type, keyGroup);
if (orderInheritance(keyGroup, this.keyGroups)){
keyGroup.insertSubClass(this.keyGroup);
this.keyGroup = keyGroup;
}
}
}
public void addKeyGroups(Collection<ATTRIBUTE_GROUP> keyGroups) {
for (ATTRIBUTE_GROUP group : keyGroups){
this.addKeyGroup(group);
}
}
public void addSubGroup(ATTRIBUTE_GROUP group) {
if (group != null){
if (this.subGroups == null){
this.subGroups = new HashMap<>();
}
if (this.group == null){
this.group = group;
}
Object type = group.getType();
if (type == null){
type = group.getTypeName();
}
if (type == null){
type = CoreClassConstants.OBJECT;
if (this.subGroups.containsKey(type)){
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("only_one_root_subgraph"));
}
}
this.subGroups.put(type, group);
if (orderInheritance(group, this.subGroups)){
group.insertSubClass(this.group);
this.group = group;
}
}
}
public CoreAttributeItem<ATTRIBUTE_GROUP> clone(Map<ATTRIBUTE_GROUP, ATTRIBUTE_GROUP> cloneMap, ATTRIBUTE_GROUP parentClone){
CoreAttributeItem clone = null;
try {
clone = (CoreAttributeItem) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError(e);
}
clone.attributeName = this.attributeName;
if (this.group != null){
clone.group = this.group.clone(cloneMap);
}
if (clone.keyGroup != null){
clone.keyGroup = this.keyGroup.clone(cloneMap);
}
clone.parent = parentClone;
if (this.subGroups != null){
clone.subGroups = new HashMap<Object, ATTRIBUTE_GROUP>();
for (Entry<Object, ATTRIBUTE_GROUP> group : this.subGroups.entrySet()){
clone.subGroups.put(group.getKey(), group.getValue().clone(cloneMap));
}
}
if (this.keyGroups != null){
clone.keyGroups = new HashMap<Object, ATTRIBUTE_GROUP>();
for (Entry<Object, ATTRIBUTE_GROUP> group : this.keyGroups.entrySet()){
clone.keyGroups.put(group.getKey(), group.getValue().clone(cloneMap));
}
}
return clone;
}
/**
* INTERNAL:
* Convert all the class-name-based settings in this Descriptor to actual class-based
* settings. This method is used when converting a project that has been built
* with class names to a project with classes.
*/
public void convertClassNamesToClasses(ClassLoader classLoader){
Map<Object, ATTRIBUTE_GROUP> newMap = new HashMap<>();
if (this.subGroups != null){
for (ATTRIBUTE_GROUP entry : this.subGroups.values()){
entry.convertClassNamesToClasses(classLoader);
if(!(entry.getSubClassGroups().isEmpty())) {
newMap.putAll(entry.getSubClassGroups());
}
newMap.put(entry.getType(), entry);
entry.setAllSubclasses(newMap);
}
}
this.subGroups = newMap;
newMap = new HashMap<>();
if (this.keyGroups != null){
for (ATTRIBUTE_GROUP entry : this.keyGroups.values()){
entry.convertClassNamesToClasses(classLoader);
newMap.put(entry.getType(), entry);
entry.setAllSubclasses(newMap);
}
}
this.keyGroups = newMap;
for (ATTRIBUTE_GROUP group : this.subGroups.values()){
if (orderInheritance(group, this.subGroups)){
group.insertSubClass(this.group);
this.group = group;
}
}
for (ATTRIBUTE_GROUP group : this.keyGroups.values()){
if (orderInheritance(group, this.keyGroups)){
group.insertSubClass(this.keyGroup);
this.keyGroup = group;
}
}
}
@Override
public boolean equals(Object obj) {
if (this != obj) {
if(obj == null) {
return false;
}
CoreAttributeItem anotherItem = null;
try {
anotherItem = (CoreAttributeItem)obj;
} catch (ClassCastException cce) {
return false;
}
if(this.subGroups != null) {
if (anotherItem.subGroups == null){
return false;
}
if (this.subGroups.size() == anotherItem.subGroups.size()){
for (Map.Entry<Object, ATTRIBUTE_GROUP> entry : this.subGroups.entrySet()){
ATTRIBUTE_GROUP anotherGroup = (ATTRIBUTE_GROUP)anotherItem.subGroups.get(entry.getKey());
if (! entry.getValue().equals(anotherGroup)){
return false;
}
}
}else{
return false;
}
} else if (anotherItem.subGroups != null){
return false;
}
if(this.keyGroups != null) {
if (anotherItem.keyGroups == null){
return false;
}
if (this.keyGroups.size() == anotherItem.keyGroups.size()){
for (Map.Entry<Object, ATTRIBUTE_GROUP> entry : this.keyGroups.entrySet()){
ATTRIBUTE_GROUP anotherGroup = (ATTRIBUTE_GROUP)anotherItem.keyGroups.get(entry.getKey());
if (! entry.getValue().equals(anotherGroup)){
return false;
}
}
}else{
return false;
}
} else if (anotherItem.keyGroups != null){
return false;
}
}
return true;
}
@Override
public int hashCode() {
int result = subGroups != null ? subGroups.hashCode() : 0;
result = 31 * result + (keyGroups != null ? keyGroups.hashCode() : 0);
return result;
}
public String getAttributeName() {
return this.attributeName;
}
public ATTRIBUTE_GROUP getGroup() {
if (this.group == null){
return null;
}
return this.group;
}
public ATTRIBUTE_GROUP getGroup(Class type) {
if (this.subGroups == null || type == null){
return null;
}
ATTRIBUTE_GROUP result = this.subGroups.get(type);
while(result == null && !type.equals(CoreClassConstants.OBJECT)){
type = type.getSuperclass();
if (type == null){
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("subclass_sought_not_a_managed_type", new Object[]{null, this.attributeName}));
}
result = this.subGroups.get(type);
}
return result;
}
public Map<Object, ATTRIBUTE_GROUP> getGroups(){
return this.subGroups;
}
public ATTRIBUTE_GROUP getKeyGroup() {
if (this.keyGroups == null){
return null;
}
return this.keyGroups.get(CoreClassConstants.OBJECT);
}
public ATTRIBUTE_GROUP getKeyGroup(Class type) {
if (this.keyGroups == null || type == null){
return null;
}
ATTRIBUTE_GROUP result = this.keyGroups.get(type);
Class currentType = type;
while(result == null && !currentType.equals(CoreClassConstants.OBJECT)){
currentType = currentType.getSuperclass();
if (currentType == null){
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("subclass_sought_not_a_managed_type", new Object[]{type, this.attributeName}));
}
result = this.keyGroups.get(currentType);
}
return result;
}
public Map<Object, ATTRIBUTE_GROUP> getKeyGroups(){
return this.keyGroups;
}
public ATTRIBUTE_GROUP getParent() {
return this.parent;
}
/**
* Will order the subGroups based on hierarchy. Returns true if the group is the new root.
* @return true if the group is the new root.
*/
protected static boolean orderInheritance(CoreAttributeGroup group, Map<Object, ? extends CoreAttributeGroup> subGroups) {
Class type = group.getType();
if (type != null){
CoreAttributeGroup superClass = null;
while (!type.equals(CoreClassConstants.OBJECT) && superClass == null){
type = type.getSuperclass();
superClass = subGroups.get(type);
}
if (superClass != null){
superClass.insertSubClass(group);
}else{
return true;
}
}
return false;
}
public void setRootGroup(ATTRIBUTE_GROUP group) {
this.group = group;
this.addSubGroup(group);
}
@Override
public String toString() {
return getClass().getSimpleName() + "(" + getAttributeName() + ")" + (this.subGroups!=null ? " => " + this.subGroups.toString() : "") + (this.keyGroups!=null ? " => " + this.keyGroups.toString() : "");
}
public String toStringNoClassName() {
return getAttributeName() + (this.subGroups!=null ? " => " + this.subGroups.toString() : "")+ (this.keyGroups!=null ? " => " + this.keyGroups.toString() : "");
}
}