| /******************************************************************************* |
| * Copyright (c) 2010, 2011 Oracle. 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: |
| * Oracle - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.jpt.common.core.internal.resource.java.binary; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Vector; |
| import org.eclipse.jdt.core.IAnnotation; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IMemberValuePair; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.dom.CompilationUnit; |
| import org.eclipse.jpt.common.core.JptCommonCorePlugin; |
| import org.eclipse.jpt.common.core.resource.java.Annotation; |
| import org.eclipse.jpt.common.core.resource.java.JavaResourceAnnotatedElement; |
| import org.eclipse.jpt.common.core.resource.java.JavaResourceNode; |
| import org.eclipse.jpt.common.core.resource.java.NestableAnnotation; |
| import org.eclipse.jpt.common.core.utility.TextRange; |
| import org.eclipse.jpt.common.utility.internal.CollectionTools; |
| import org.eclipse.jpt.common.utility.internal.iterables.CompositeIterable; |
| import org.eclipse.jpt.common.utility.internal.iterables.EmptyListIterable; |
| import org.eclipse.jpt.common.utility.internal.iterables.ListIterable; |
| import org.eclipse.jpt.common.utility.internal.iterables.LiveCloneIterable; |
| import org.eclipse.jpt.common.utility.internal.iterables.LiveCloneListIterable; |
| import org.eclipse.jpt.common.utility.internal.iterables.TransformationIterable; |
| |
| /** |
| * binary annotated element |
| */ |
| abstract class BinaryAnnotatedElement |
| extends BinaryNode |
| implements JavaResourceAnnotatedElement |
| { |
| /** JDT annotated element adapter */ |
| final Adapter adapter; |
| |
| /** annotations */ |
| final Vector<Annotation> annotations = new Vector<Annotation>(); |
| |
| /** |
| * Annotation containers keyed on nestable annotation name. |
| * This is used to store annotations that can be both standalone and nested |
| * and are moved back and forth between the 2. |
| */ |
| final Map<String, AnnotationContainer> annotationContainers = new HashMap<String, AnnotationContainer>(); |
| |
| /** |
| * these are built as needed |
| */ |
| private final HashMap<String, Annotation> nullAnnotationsCache = new HashMap<String, Annotation>(); |
| |
| |
| // ********** construction/initialization ********** |
| |
| public BinaryAnnotatedElement(JavaResourceNode parent, Adapter adapter) { |
| super(parent); |
| this.adapter = adapter; |
| this.initializeAnnotations(); |
| } |
| |
| private void initializeAnnotations() { |
| for (IAnnotation annotation : this.getJdtAnnotations()) { |
| this.addAnnotation(annotation); |
| } |
| } |
| |
| private void addAnnotation(IAnnotation jdtAnnotation) { |
| String jdtAnnotationName = jdtAnnotation.getElementName(); |
| if (this.annotationIsValid(jdtAnnotationName)) { |
| this.annotations.add(this.getAnnotationProvider().buildAnnotation(this, jdtAnnotation)); |
| } |
| if (this.annotationIsValidNestable(jdtAnnotationName)) { |
| AnnotationContainer container = new AnnotationContainer(); |
| container.initializeFromNestableAnnotation(jdtAnnotation); |
| this.annotationContainers.put(jdtAnnotationName, container); |
| } |
| if (this.annotationIsValidContainer(jdtAnnotationName)) { |
| String nestableAnnotationName = this.getNestableAnnotationName(jdtAnnotationName); |
| AnnotationContainer container = new AnnotationContainer(); |
| container.initializeFromContainerAnnotation(jdtAnnotation); |
| this.annotationContainers.put(nestableAnnotationName, container); |
| } |
| } |
| |
| private boolean annotationIsValid(String annotationName) { |
| return CollectionTools.contains(this.getValidAnnotationNames(), annotationName); |
| } |
| |
| private boolean annotationIsValidContainer(String annotationName) { |
| return CollectionTools.contains(this.getValidContainerAnnotationNames(), annotationName); |
| } |
| |
| private boolean annotationIsValidNestable(String annotationName) { |
| return CollectionTools.contains(this.getValidNestableAnnotationNames(), annotationName); |
| } |
| |
| Iterable<String> getValidAnnotationNames() { |
| return this.getAnnotationProvider().getAnnotationNames(); |
| } |
| |
| Iterable<String> getValidContainerAnnotationNames() { |
| return this.getAnnotationProvider().getContainerAnnotationNames(); |
| } |
| |
| Iterable<String> getValidNestableAnnotationNames() { |
| return this.getAnnotationProvider().getNestableAnnotationNames(); |
| } |
| |
| |
| private String getNestableAnnotationName(String containerAnnotationName) { |
| return getAnnotationProvider().getNestableAnnotationName(containerAnnotationName); |
| } |
| |
| |
| // ********** updating ********** |
| |
| @Override |
| public void update() { |
| super.update(); |
| this.updateAnnotations(); |
| } |
| |
| // TODO |
| private void updateAnnotations() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| |
| // ********** annotations ********** |
| |
| public Iterable<Annotation> getAnnotations() { |
| return new LiveCloneIterable<Annotation>(this.annotations); |
| } |
| |
| public int getAnnotationsSize() { |
| return this.annotations.size(); |
| } |
| |
| protected Iterable<NestableAnnotation> getNestableAnnotations() { |
| return new CompositeIterable<NestableAnnotation>(this.getNestableAnnotationLists()); |
| } |
| |
| private Iterable<Iterable<NestableAnnotation>> getNestableAnnotationLists() { |
| return new TransformationIterable<AnnotationContainer, Iterable<NestableAnnotation>>(this.annotationContainers.values()) { |
| @Override |
| protected Iterable<NestableAnnotation> transform(AnnotationContainer container) { |
| return container.getNestedAnnotations(); |
| } |
| }; |
| } |
| |
| public Annotation getAnnotation(String annotationName) { |
| return this.selectAnnotationNamed(this.getAnnotations(), annotationName); |
| } |
| |
| public Annotation getNonNullAnnotation(String annotationName) { |
| Annotation annotation = this.getAnnotation(annotationName); |
| return (annotation != null) ? annotation : this.getNullAnnotation(annotationName); |
| } |
| |
| private synchronized Annotation getNullAnnotation(String annotationName) { |
| Annotation annotation = this.nullAnnotationsCache.get(annotationName); |
| if (annotation == null) { |
| annotation = this.buildNullAnnotation(annotationName); |
| this.nullAnnotationsCache.put(annotationName, annotation); |
| } |
| return annotation; |
| } |
| |
| private Annotation buildNullAnnotation(String annotationName) { |
| return getAnnotationProvider().buildNullAnnotation(this, annotationName); |
| } |
| |
| // ********** nestable annotations ********** |
| |
| public ListIterable<NestableAnnotation> getAnnotations(String nestableAnnotationName) { |
| AnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); |
| return container != null ? container.getNestedAnnotations() : EmptyListIterable.<NestableAnnotation> instance(); |
| } |
| |
| |
| public int getAnnotationsSize(String nestableAnnotationName) { |
| AnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); |
| return container == null ? 0 : container.getNestedAnnotationsSize(); |
| } |
| |
| public NestableAnnotation getAnnotation(int index, String nestableAnnotationName) { |
| AnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); |
| return container == null ? null : container.nestedAnnotationAt(index); |
| } |
| |
| // ***** queries ***** |
| |
| public Iterable<Annotation> getAllAnnotations() { |
| return new CompositeIterable<Annotation>( |
| getAnnotations(), |
| getContainerOrNestableAnnotations()); |
| } |
| |
| protected Iterable<Annotation> getContainerOrNestableAnnotations() { |
| return new TransformationIterable<AnnotationContainer, Annotation>(this.annotationContainers.values()) { |
| @Override |
| protected Annotation transform(AnnotationContainer o) { |
| return (o.getContainerAnnotation() != null) ? o.getContainerAnnotation() : CollectionTools.get(o.getNestedAnnotations(), 0); |
| } |
| }; |
| } |
| |
| public boolean isAnnotated() { |
| return ! (this.annotations.isEmpty() && this.annotationContainers.isEmpty()); |
| } |
| |
| public boolean isAnnotatedWith(Iterable<String> annotationNames) { |
| for (Annotation annotation : this.getAnnotations()) { |
| if (CollectionTools.contains(annotationNames, annotation.getAnnotationName())) { |
| return true; |
| } |
| } |
| for (Annotation annotation : this.getNestableAnnotations()) { |
| if (CollectionTools.contains(annotationNames, annotation.getAnnotationName())) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| // ********** misc ********** |
| |
| IJavaElement getAnnotatedElement() { |
| return this.adapter.getElement(); |
| } |
| |
| private Annotation selectAnnotationNamed(Iterable<Annotation> annotationList, String annotationName) { |
| for (Annotation annotation : annotationList) { |
| if (annotation.getAnnotationName().equals(annotationName)) { |
| return annotation; |
| } |
| } |
| return null; |
| } |
| |
| private IAnnotation[] getJdtAnnotations() { |
| try { |
| return this.adapter.getAnnotations(); |
| } catch (JavaModelException ex) { |
| JptCommonCorePlugin.log(ex); |
| return EMPTY_JDT_ANNOTATION_ARRAY; |
| } |
| } |
| private static final IAnnotation[] EMPTY_JDT_ANNOTATION_ARRAY = new IAnnotation[0]; |
| |
| |
| // ********** IJavaElement adapter ********** |
| |
| interface Adapter { |
| /** |
| * Return the adapter's JDT element (IPackageFragment, IType, IField, IMethod). |
| */ |
| IJavaElement getElement(); |
| |
| /** |
| * Return the adapter's element's JDT annotations. |
| */ |
| IAnnotation[] getAnnotations() throws JavaModelException; |
| } |
| |
| |
| // ********** unsupported JavaResourcePersistentMember implementation ********** |
| |
| public Annotation addAnnotation(String annotationName) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public NestableAnnotation addAnnotation(int index, String nestableAnnotationName) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public void moveAnnotation(int targetIndex, int sourceIndex, String nestableAnnotationName) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public void removeAnnotation(String annotationName) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public void removeAnnotation(int index, String nestableAnnotationName) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public TextRange getNameTextRange(CompilationUnit astRoot) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public TextRange getTextRange(String nestableAnnotationName, CompilationUnit astRoot) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| private static final IMemberValuePair[] EMPTY_MEMBER_VALUE_PAIR_ARRAY = new IMemberValuePair[0]; |
| |
| |
| class AnnotationContainer { |
| |
| private Annotation containerAnnotation; |
| |
| private final Vector<NestableAnnotation> nestedAnnotations = new Vector<NestableAnnotation>(); |
| |
| protected AnnotationContainer() { |
| super(); |
| } |
| |
| |
| // ***** init from container ***** |
| |
| protected void initializeFromContainerAnnotation(IAnnotation jdtContainerAnnotation) { |
| this.containerAnnotation = |
| BinaryAnnotatedElement.this.getAnnotationProvider().buildAnnotation( |
| BinaryAnnotatedElement.this, jdtContainerAnnotation); |
| initializeNestedAnnotations(jdtContainerAnnotation); |
| } |
| |
| protected void initializeNestedAnnotations(IAnnotation jdtContainerAnnotation) { |
| int index = 0; |
| for (IMemberValuePair valuePair : this.getJdtMemberValuePairs(jdtContainerAnnotation)) { |
| IAnnotation jdtNestedAnnotation = (IAnnotation) valuePair.getValue(); |
| this.nestedAnnotations.add( |
| BinaryAnnotatedElement.this.getAnnotationProvider().buildAnnotation( |
| BinaryAnnotatedElement.this, jdtNestedAnnotation, index++)); |
| } |
| } |
| |
| private IMemberValuePair[] getJdtMemberValuePairs(IAnnotation jdtContainerAnnotation) { |
| try { |
| return jdtContainerAnnotation.getMemberValuePairs(); |
| } |
| catch (JavaModelException ex) { |
| JptCommonCorePlugin.log(ex); |
| return EMPTY_MEMBER_VALUE_PAIR_ARRAY; |
| } |
| } |
| |
| |
| // ***** init from nestable ***** |
| |
| protected void initializeFromNestableAnnotation(IAnnotation jdtNestableAnnotation) { |
| this.nestedAnnotations.add( |
| BinaryAnnotatedElement.this.getAnnotationProvider().buildAnnotation( |
| BinaryAnnotatedElement.this, jdtNestableAnnotation, 0)); |
| } |
| |
| |
| // ***** queries ***** |
| |
| protected Annotation getContainerAnnotation() { |
| return this.containerAnnotation; |
| } |
| |
| protected ListIterable<NestableAnnotation> getNestedAnnotations() { |
| return new LiveCloneListIterable<NestableAnnotation>(this.nestedAnnotations); |
| } |
| |
| protected int getNestedAnnotationsSize() { |
| return this.nestedAnnotations.size(); |
| } |
| |
| protected NestableAnnotation nestedAnnotationAt(int index) { |
| return this.nestedAnnotations.get(index); |
| } |
| } |
| } |