/*******************************************************************************
* Copyright (c) 2004, 2010 BREDEX GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BREDEX GmbH - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.jubula.client.core.model;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.Version;
import org.apache.commons.lang.Validate;
import org.eclipse.jubula.client.core.businessprocess.CompNameManager;
import org.eclipse.jubula.client.core.businessprocess.ObjectMappingEventDispatcher;
import org.eclipse.jubula.client.core.i18n.Messages;
import org.eclipse.jubula.client.core.utils.ObjectMappingUtil;
import org.eclipse.jubula.tools.internal.messagehandling.MessageIDs;
import org.eclipse.jubula.tools.internal.objects.IComponentIdentifier;
import org.eclipse.osgi.util.NLS;
import org.eclipse.persistence.annotations.BatchFetch;
import org.eclipse.persistence.annotations.BatchFetchType;
/**
*
* @author BREDEX GmbH
* @created 07.04.2005
*/
@Entity
@Table(name = "OBJ_MAP")
class ObjectMappingPO implements IObjectMappingPO {
/** Persistence (JPA / EclipseLink) OID */
private transient Long m_id = null;
/** Persistence (JPA / EclipseLink) version id */
private transient Integer m_version = null;
/** The ID of the parent project */
private Long m_parentProjectId = null;
/** The timestamp */
private long m_timestamp = 0;
/** the profile used for this object map */
private IObjectMappingProfilePO m_profile = null;
/** the top-level category for mapped components */
private IObjectMappingCategoryPO m_mappedCategory;
/** the top-level category for unmapped component names */
private IObjectMappingCategoryPO m_unmappedLogicalCategory;
/** the top-level category for unmapped technical names */
private IObjectMappingCategoryPO m_unmappedTechnicalCategory;
/** cache for mappings */
private Set<IObjectMappingAssoziationPO> m_mappings;
/** faster assoc lookup */
private Map<String, IObjectMappingAssoziationPO> m_logicalNameToAssoc;
/** default constructor (for Persistence (JPA / EclipseLink)) */
@SuppressWarnings("unused")
private ObjectMappingPO() {
m_logicalNameToAssoc = new HashMap<String, IObjectMappingAssoziationPO>(
1001);
}
/**
* Constructor
*
* @param mappedCategory
* The top-level category for mapped components.
* @param unmappedLogicalCategory
* The top-level category for unmapped component names.
* @param unmappedTechnicalCategory
* The top-level category for unmapped technical names.
*/
ObjectMappingPO(IObjectMappingCategoryPO mappedCategory,
IObjectMappingCategoryPO unmappedLogicalCategory,
IObjectMappingCategoryPO unmappedTechnicalCategory) {
m_mappedCategory = mappedCategory;
m_unmappedLogicalCategory = unmappedLogicalCategory;
m_unmappedTechnicalCategory = unmappedTechnicalCategory;
m_logicalNameToAssoc = new HashMap<String, IObjectMappingAssoziationPO>(
1001);
}
/**
* tries to assign a logical(perhaps existing) to a technical(perhaps existing)
* @param logic logical name
* @param technical technical name
* @return ObjectMappingAssoziationPO
*/
public IObjectMappingAssoziationPO addObjectMappingAssoziation(String logic,
IComponentIdentifier technical) {
IObjectMappingAssoziationPO oma = assignLogicalToTechnicalName(logic,
technical);
IObjectMappingCategoryPO assocSection = oma.getSection();
IObjectMappingCategoryPO mappedSection = getMappedCategory();
if (mappedSection == null || !mappedSection.equals(assocSection)) {
// Association is not already in the "mapped" section.
// This is because either:
// a. the association is new, or
// b. the association is currently "unmapped"
IObjectMappingCategoryPO catToCreateIn =
ObjectMappingEventDispatcher.getCategoryToCreateIn();
// Remove the association from its current category, if it has one
IObjectMappingCategoryPO currentCategory = oma.getCategory();
if (currentCategory != null) {
currentCategory.removeAssociation(oma);
}
if (catToCreateIn != null) {
catToCreateIn.addAssociation(oma);
} else {
getMappedCategory().addAssociation(oma);
}
}
oma.setParentProjectId(getParentProjectId());
return oma;
}
/**
* @param assoc the association to remove
*/
public void removeAssociationFromCache(IObjectMappingAssoziationPO assoc) {
if (m_mappings != null) {
m_mappings.remove(assoc);
}
for (String logicalName : assoc.getLogicalNames()) {
m_logicalNameToAssoc.remove(logicalName);
}
}
/**
* Creates a new technical Name, unassigned
* @param tech ComponentIdentifier
* @param aut AUTMainPO
* @return ObjectMappingAssoziationPO
*/
public IObjectMappingAssoziationPO
addTechnicalName(IComponentIdentifier tech, IAUTMainPO aut) {
if (!existTechnicalName(tech)) {
IObjectMappingAssoziationPO asso = PoMaker
.createObjectMappingAssoziationPO(tech);
if (aut != null) {
IObjectMappingCategoryPO categoryToCreateIn =
ObjectMappingEventDispatcher.getCategoryToCreateIn();
if (categoryToCreateIn != null) {
categoryToCreateIn.addAssociation(asso);
} else {
getUnmappedTechnicalCategory().addAssociation(asso);
}
}
asso.setParentProjectId(getParentProjectId());
return asso;
}
return null;
}
/**
* tries to assign a logical(perhaps existing) to a technical(perhaps existing)
* @param logic logical name
* @param technical technical name
* @return ObjectMappingAssoziationPO
*/
public IObjectMappingAssoziationPO assignLogicalToTechnicalName(
String logic, IComponentIdentifier technical) {
IObjectMappingAssoziationPO oma = null;
if (existLogicalName(logic)) {
oma = getLogicalNameAssoc(logic);
oma.removeLogicalName(logic);
if (oma.getLogicalNames().size() == 0
&& oma.getTechnicalName() == null) {
getMappings().remove(oma);
}
}
if (!existTechnicalName(technical)) {
oma = PoMaker.createObjectMappingAssoziationPO(technical, logic);
} else {
for (IObjectMappingAssoziationPO assoc : getMappings()) {
oma = assoc;
if (technical.equals(oma.getTechnicalName())) {
oma.addLogicalName(logic);
break;
}
}
}
oma.setParentProjectId(getParentProjectId());
return oma;
}
/**
* Check if a technical name exists
*
* @param technical
* technical name
* @return boolean
*/
public boolean existTechnicalName(IComponentIdentifier technical) {
for (IObjectMappingAssoziationPO oma : getMappings()) {
if (technical.equals(oma.getTechnicalName())) {
return true;
}
}
return false;
}
/**
* Check if a logical name exists
* @param logical logical name
* @return boolean
*/
private boolean existLogicalName(String logical) {
return getLogicalNameAssoc(logical) != null;
}
/**
*
* @param compNameGuid The GUID of the Component Name for which to find the
* association.
* @return the Association for the Component Name with the given GUID, or
* <code>null</code> if no such Association exists in this Object
* Mapping.
*/
public IObjectMappingAssoziationPO getLogicalNameAssoc(
String compNameGuid) {
IObjectMappingAssoziationPO res =
m_logicalNameToAssoc.get(compNameGuid);
if (res != null) {
return res;
}
for (IObjectMappingAssoziationPO assoc : getMappings()) {
if (assoc.getLogicalNames().contains(compNameGuid)) {
m_logicalNameToAssoc.put(compNameGuid, assoc);
return assoc;
}
}
return null;
}
/**
* gives back the number of technical names
* @return int
*/
@Transient
public int getTechnicalNamesSize() {
int size = 0;
for (IObjectMappingAssoziationPO oma : getMappings()) {
if (oma.getTechnicalName() != null) {
size++;
}
}
return size;
}
/**
* @param logical
* String
* @throws LogicComponentNotManagedException
* error
* @return the technicalName to a logical name or <code>null</code>
*/
public IComponentIdentifier getTechnicalName(String logical) throws
LogicComponentNotManagedException {
IObjectMappingAssoziationPO asso = getLogicalNameAssoc(logical);
if (asso == null) {
// Check for default mapping
IComponentNamePO compNamePo =
CompNameManager.getInstance().getResCompNamePOByGuid(logical);
if (compNamePo != null) {
asso = getLogicalNameAssoc(compNamePo.getName());
}
}
if (asso == null) {
throw new LogicComponentNotManagedException(
NLS.bind(Messages.TheLogicComponentIsNotManaged, logical),
MessageIDs.E_COMPONENT_NOT_MANAGED);
}
return ObjectMappingUtil.createCompIdentifierFromAssoziation(asso);
}
/**
* @return Set
*/
@Transient
public Set<IObjectMappingAssoziationPO> getMappings() {
if (m_mappings == null) {
/*
* Keep in mind the the getXXXCategory() calls will clear the
* mappings cache by setting m_mapping to null. To prevent
* a NPE we can't use m_mapping while building the map.
*/
Set<IObjectMappingAssoziationPO> mappings =
new HashSet<IObjectMappingAssoziationPO>();
addAssociations(mappings, getMappedCategory());
addAssociations(mappings, getUnmappedLogicalCategory());
addAssociations(mappings, getUnmappedTechnicalCategory());
m_mappings = mappings;
}
return m_mappings;
}
/** {@inheritDoc} */
public void addAssociationToCache(IObjectMappingAssoziationPO assoc) {
getMappings().add(assoc);
for (String guid : assoc.getLogicalNames()) {
m_logicalNameToAssoc.put(guid, assoc);
}
}
/**
* clears the precomputed mappings cache
*/
private void clearMappingsCache() {
m_logicalNameToAssoc.clear();
m_mappings = null;
}
/**
* Recursively adds all associations from <code>category</code> and all
* subcategories to <code>assocSet</code>.
*
* @param assocSet The collection to which the associations will be added.
* @param category The category in which to search for associations to add.
*/
private void addAssociations(Set<IObjectMappingAssoziationPO> assocSet,
IObjectMappingCategoryPO category) {
Validate.noNullElements(category.getUnmodifiableAssociationList());
assocSet.addAll(category.getUnmodifiableAssociationList());
for (IObjectMappingCategoryPO subcategory
: category.getUnmodifiableCategoryList()) {
addAssociations(assocSet, subcategory);
}
}
/**
* only for Persistence (JPA / EclipseLink)
*
* @return Returns the id.
*/
@Id
@GeneratedValue
public Long getId() {
return m_id;
}
/**
* only for Persistence (JPA / EclipseLink)
* @param id The id to set.
*/
@SuppressWarnings("unused")
private void setId(Long id) {
m_id = id;
}
/**
*
* {@inheritDoc}
*/
@Transient
public Long getParentProjectId() {
return getHbmParentProjectId();
}
/**
*
* {@inheritDoc}
*/
public void setParentProjectId(Long projectId) {
setHbmParentProjectId(projectId);
for (IObjectMappingAssoziationPO assoPO : getMappings()) {
assoPO.setParentProjectId(projectId);
}
}
/**
*
* {@inheritDoc}
*/
@Basic
@Column(name = "PARENT_PROJ")
Long getHbmParentProjectId() {
return m_parentProjectId;
}
/**
*
* {@inheritDoc}
*/
void setHbmParentProjectId(Long projectId) {
m_parentProjectId = projectId;
}
/**
*
* {@inheritDoc}
*/
@Version
public Integer getVersion() {
return m_version;
}
/**
* @param version version
*/
@SuppressWarnings("unused")
private void setVersion(Integer version) {
m_version = version;
}
/**
* {@inheritDoc}
* @return string representation of this object
*/
@Transient
public String getName() {
return this.toString();
}
/**
*
* {@inheritDoc}
*/
@Basic
@Column(name = "TIMESTAMP")
public long getTimestamp() {
return m_timestamp;
}
/**
* {@inheritDoc}
*/
public void setTimestamp(long timestamp) {
m_timestamp = timestamp;
}
/**
*
* {@inheritDoc}
*/
@Transient
public IObjectMappingProfilePO getProfile() {
return getHbmProfile();
}
/**
*
* {@inheritDoc}
*/
public void setProfile(IObjectMappingProfilePO profile) {
setHbmProfile(profile);
}
/**
*
* @return the profile being used for this object map.
*/
@ManyToOne(targetEntity = ObjectMappingProfilePO.class, optional = false,
cascade = CascadeType.ALL)
@JoinColumn(name = "FK_PROFILE")
private IObjectMappingProfilePO getHbmProfile() {
return m_profile;
}
/**
*
* @param profile the profile that this object map will use.
*/
private void setHbmProfile(IObjectMappingProfilePO profile) {
m_profile = profile;
}
/**
*
* {@inheritDoc}
*/
@OneToOne(targetEntity = ObjectMappingCategoryPO.class,
cascade = CascadeType.ALL, fetch = FetchType.EAGER,
optional = false)
@BatchFetch(value = BatchFetchType.JOIN)
public IObjectMappingCategoryPO getMappedCategory() {
clearMappingsCache(); // may be changed outside of class
return m_mappedCategory;
}
/**
* For Persistence (JPA / EclipseLink).
*
* @param mappedCategory The new top-level category for mapped components.
*/
@SuppressWarnings("unused")
private void setMappedCategory(IObjectMappingCategoryPO mappedCategory) {
m_mappedCategory = mappedCategory;
clearMappingsCache();
}
/**
*
* {@inheritDoc}
*/
@OneToOne(targetEntity = ObjectMappingCategoryPO.class,
cascade = CascadeType.ALL, fetch = FetchType.EAGER,
optional = false)
@BatchFetch(value = BatchFetchType.JOIN)
public IObjectMappingCategoryPO getUnmappedLogicalCategory() {
clearMappingsCache(); // may be changed outside of class
return m_unmappedLogicalCategory;
}
/**
* For Persistence (JPA / EclipseLink).
*
* @param unmappedLogicalCategory The new top-level category for
* unmapped component names.
*/
@SuppressWarnings("unused")
private void setUnmappedLogicalCategory(
IObjectMappingCategoryPO unmappedLogicalCategory) {
m_unmappedLogicalCategory = unmappedLogicalCategory;
clearMappingsCache();
}
/**
*
* {@inheritDoc}
*/
@OneToOne(targetEntity = ObjectMappingCategoryPO.class,
cascade = CascadeType.ALL, fetch = FetchType.EAGER,
optional = false)
@BatchFetch(value = BatchFetchType.JOIN)
public IObjectMappingCategoryPO getUnmappedTechnicalCategory() {
clearMappingsCache(); // may be changed outside of class
return m_unmappedTechnicalCategory;
}
/**
* For Persistence (JPA / EclipseLink).
*
* @param unmappedTechnicalCategory The new top-level category for
* unmapped technical names.
*/
@SuppressWarnings("unused")
private void setUnmappedTechnicalCategory(
IObjectMappingCategoryPO unmappedTechnicalCategory) {
m_unmappedTechnicalCategory = unmappedTechnicalCategory;
clearMappingsCache();
}
}