/*******************************************************************************
* Copyright (c) 2011 Gerd Wuetherich (gerd@gerd-wuetherich.de).
* 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:
* Gerd Wuetherich (gerd@gerd-wuetherich.de) - initial API and implementation
******************************************************************************/
package org.bundlemaker.core.jtype.internal;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.bundlemaker.core.jtype.IReferenceRecorder;
import org.bundlemaker.core.jtype.JavaTypeUtils;
import org.bundlemaker.core.jtype.ReferenceAttributes;
import org.eclipse.core.runtime.Assert;
/**
* <p>
* </p>
*
* @author Gerd Wütherich (gerd@gerd-wuetherich.de)
*/
public abstract class ReferenceContainer implements IReferenceRecorder {
/** the fly weight cahce */
private transient FlyWeightReferenceCache _flyWeightCache;
/** the reference map */
private Map<ReferenceKey, Reference> _referenceMap;
/** the references */
private Set<Reference> _references;
/**
* <p>
* Creates a new instance of type {@link ReferenceContainer}.
* </p>
*
* @param cache
*/
public ReferenceContainer(FlyWeightReferenceCache cache) {
Assert.isNotNull(cache);
//
_flyWeightCache = cache;
_referenceMap = new HashMap<ReferenceKey, Reference>();
}
/**
* <p>
* </p>
*
* @return
*/
protected abstract Set<Reference> createReferencesSet();
/**
* <p>
* </p>
*
* @param fullyQualifiedName
*/
@Override
public void recordReference(String fullyQualifiedName, ReferenceAttributes requestedAttributes) {
//
Assert.isNotNull(fullyQualifiedName);
Assert.isNotNull(requestedAttributes);
//
if (fullyQualifiedName.startsWith("java.")) {
// do nothing
return;
}
// if the referenced type is an local or anonymous class,
// we redirect the dependency to the outer type
if (JavaTypeUtils.isLocalOrAnonymousTypeName(fullyQualifiedName)) {
// set the references
fullyQualifiedName = JavaTypeUtils.getEnclosingNonLocalAndNonAnonymousTypeName(fullyQualifiedName);
// create new attributes
requestedAttributes = new ReferenceAttributes(requestedAttributes.getReferenceType(), false, false, false,
requestedAttributes.isCompileTime(), requestedAttributes.isRuntimeTime(),
requestedAttributes.isDirectlyReferenced(), requestedAttributes.isIndirectlyReferenced());
}
// create the key
Assert.isNotNull(requestedAttributes);
ReferenceKey key = new ReferenceKey(fullyQualifiedName, requestedAttributes.getReferenceType());
// get the reference
Assert.isNotNull(_referenceMap, "Reference Map is null");
Reference existingReference = _referenceMap.get(key);
Assert.isNotNull(_flyWeightCache, "_flyWeightCache is not set!");
// create completely new one
if (existingReference == null) {
existingReference = _flyWeightCache.getReference(fullyQualifiedName, requestedAttributes);
references().add(existingReference);
_referenceMap.put(key, existingReference);
return;
}
// return if current dependency matches the requested one
if (existingReference.getReferenceAttributes().equals(requestedAttributes)) {
return;
}
// if current dependency does not match the requested one, we have to
// request a new one
references().remove(existingReference);
ReferenceAttributes mergedAttributes = merge(requestedAttributes, existingReference.getReferenceAttributes());
existingReference = _flyWeightCache.getReference(fullyQualifiedName, mergedAttributes);
references().add(existingReference);
_referenceMap.put(key, existingReference);
}
/**
* <p>
* </p>
*
* @param a1
* @param a2
* @return
*/
private ReferenceAttributes merge(ReferenceAttributes a1, ReferenceAttributes a2) {
//
return new ReferenceAttributes(a1.getReferenceType(), a1.isExtends() || a2.isExtends(), a1.isImplements()
|| a2.isImplements(), a1.isClassAnnotation() || a2.isClassAnnotation(), a1.isCompileTime()
|| a2.isCompileTime(), a1.isRuntimeTime() || a2.isRuntimeTime(), a1.isDirectlyReferenced()
|| a2.isDirectlyReferenced(), a1.isIndirectlyReferenced() || a2.isIndirectlyReferenced());
}
/**
* <p>
* </p>
*
* @return
*/
private Set<Reference> references() {
// create if necessary
if (_references == null) {
_references = createReferencesSet();
}
// return the references
return _references;
}
}