diff --git a/enterprise/j2ee.api.ejbmodule/nbproject/project.xml b/enterprise/j2ee.api.ejbmodule/nbproject/project.xml index 67806c00d601..32419ba3813d 100644 --- a/enterprise/j2ee.api.ejbmodule/nbproject/project.xml +++ b/enterprise/j2ee.api.ejbmodule/nbproject/project.xml @@ -247,6 +247,7 @@ org.netbeans.modules.maven.jaxws org.netbeans.modules.profiler.j2ee org.netbeans.modules.web.beans + org.netbeans.modules.jakarta.web.beans org.netbeans.modules.web.project org.netbeans.modules.websvc.core org.netbeans.modules.websvc.dev diff --git a/enterprise/j2ee.common/nbproject/project.xml b/enterprise/j2ee.common/nbproject/project.xml index 9c5939c006ff..7ce39afc5dc6 100644 --- a/enterprise/j2ee.common/nbproject/project.xml +++ b/enterprise/j2ee.common/nbproject/project.xml @@ -522,6 +522,7 @@ org.netbeans.modules.visualweb.dataconnectivity org.netbeans.modules.visualweb.project.jsf org.netbeans.modules.web.beans + org.netbeans.modules.jakarta.web.beans org.netbeans.modules.web.core org.netbeans.modules.web.freeform org.netbeans.modules.web.jsf diff --git a/enterprise/jakarta.web.beans/build.xml b/enterprise/jakarta.web.beans/build.xml new file mode 100644 index 000000000000..bb0563e052d1 --- /dev/null +++ b/enterprise/jakarta.web.beans/build.xml @@ -0,0 +1,25 @@ + + + + Builds, tests, and runs the project org.netbeans.modules.jakarta.web.beans + + diff --git a/enterprise/jakarta.web.beans/licenseinfo.xml b/enterprise/jakarta.web.beans/licenseinfo.xml new file mode 100644 index 000000000000..fb786cf0fc7b --- /dev/null +++ b/enterprise/jakarta.web.beans/licenseinfo.xml @@ -0,0 +1,39 @@ + + + + + src/org/netbeans/modules/jakarta/web/beans/resources/delegate.png + src/org/netbeans/modules/jakarta/web/beans/resources/injection_point.png + src/org/netbeans/modules/jakarta/web/beans/resources/event.png + src/org/netbeans/modules/jakarta/web/beans/resources/observer.png + + + + + src/org/netbeans/modules/jakarta/web/beans/resources/Interceptor.template + src/org/netbeans/modules/jakarta/web/beans/resources/Qualifier.template + src/org/netbeans/modules/jakarta/web/beans/resources/Scope.template + src/org/netbeans/modules/jakarta/web/beans/resources/Stereotype.template + + + + diff --git a/enterprise/jakarta.web.beans/manifest.mf b/enterprise/jakarta.web.beans/manifest.mf new file mode 100644 index 000000000000..3a8ae23a8cb9 --- /dev/null +++ b/enterprise/jakarta.web.beans/manifest.mf @@ -0,0 +1,6 @@ +Manifest-Version: 1.0 +OpenIDE-Module: org.netbeans.modules.jakarta.web.beans/1 +OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/jakarta/web/beans/resources/Bundle.properties +OpenIDE-Module-Layer: org/netbeans/modules/jakarta/web/beans/resources/layer.xml +OpenIDE-Module-Specification-Version: 2.38 +AutoUpdate-Show-In-Client: false diff --git a/enterprise/jakarta.web.beans/nbproject/org-netbeans-modules-jakarta-web-beans.sig b/enterprise/jakarta.web.beans/nbproject/org-netbeans-modules-jakarta-web-beans.sig new file mode 100644 index 000000000000..329df3b5bcee --- /dev/null +++ b/enterprise/jakarta.web.beans/nbproject/org-netbeans-modules-jakarta-web-beans.sig @@ -0,0 +1,539 @@ +#Signature file v4.1 +#Version 2.38 + +CLSS public java.beans.FeatureDescriptor +cons public init() +meth public boolean isExpert() +meth public boolean isHidden() +meth public boolean isPreferred() +meth public java.lang.Object getValue(java.lang.String) +meth public java.lang.String getDisplayName() +meth public java.lang.String getName() +meth public java.lang.String getShortDescription() +meth public java.lang.String toString() +meth public java.util.Enumeration attributeNames() +meth public void setDisplayName(java.lang.String) +meth public void setExpert(boolean) +meth public void setHidden(boolean) +meth public void setName(java.lang.String) +meth public void setPreferred(boolean) +meth public void setShortDescription(java.lang.String) +meth public void setValue(java.lang.String,java.lang.Object) +supr java.lang.Object + +CLSS public abstract interface java.io.Serializable + +CLSS public abstract interface java.lang.Comparable<%0 extends java.lang.Object> +meth public abstract int compareTo({java.lang.Comparable%0}) + +CLSS public abstract java.lang.Enum<%0 extends java.lang.Enum<{java.lang.Enum%0}>> +cons protected init(java.lang.String,int) +intf java.io.Serializable +intf java.lang.Comparable<{java.lang.Enum%0}> +meth protected final java.lang.Object clone() throws java.lang.CloneNotSupportedException +meth protected final void finalize() +meth public final boolean equals(java.lang.Object) +meth public final int compareTo({java.lang.Enum%0}) +meth public final int hashCode() +meth public final int ordinal() +meth public final java.lang.Class<{java.lang.Enum%0}> getDeclaringClass() +meth public final java.lang.String name() +meth public java.lang.String toString() +meth public static <%0 extends java.lang.Enum<{%%0}>> {%%0} valueOf(java.lang.Class<{%%0}>,java.lang.String) +supr java.lang.Object + +CLSS public java.lang.Exception +cons protected init(java.lang.String,java.lang.Throwable,boolean,boolean) +cons public init() +cons public init(java.lang.String) +cons public init(java.lang.String,java.lang.Throwable) +cons public init(java.lang.Throwable) +supr java.lang.Throwable + +CLSS public java.lang.Object +cons public init() +meth protected java.lang.Object clone() throws java.lang.CloneNotSupportedException +meth protected void finalize() throws java.lang.Throwable +meth public boolean equals(java.lang.Object) +meth public final java.lang.Class getClass() +meth public final void notify() +meth public final void notifyAll() +meth public final void wait() throws java.lang.InterruptedException +meth public final void wait(long) throws java.lang.InterruptedException +meth public final void wait(long,int) throws java.lang.InterruptedException +meth public int hashCode() +meth public java.lang.String toString() + +CLSS public java.lang.Throwable +cons protected init(java.lang.String,java.lang.Throwable,boolean,boolean) +cons public init() +cons public init(java.lang.String) +cons public init(java.lang.String,java.lang.Throwable) +cons public init(java.lang.Throwable) +intf java.io.Serializable +meth public final java.lang.Throwable[] getSuppressed() +meth public final void addSuppressed(java.lang.Throwable) +meth public java.lang.StackTraceElement[] getStackTrace() +meth public java.lang.String getLocalizedMessage() +meth public java.lang.String getMessage() +meth public java.lang.String toString() +meth public java.lang.Throwable fillInStackTrace() +meth public java.lang.Throwable getCause() +meth public java.lang.Throwable initCause(java.lang.Throwable) +meth public void printStackTrace() +meth public void printStackTrace(java.io.PrintStream) +meth public void printStackTrace(java.io.PrintWriter) +meth public void setStackTrace(java.lang.StackTraceElement[]) +supr java.lang.Object + +CLSS public org.netbeans.modules.jakarta.web.beans.BeansDataObject +cons public init(org.openide.filesystems.FileObject,org.openide.loaders.MultiFileLoader) throws java.io.IOException +meth protected int associateLookup() +supr org.openide.loaders.MultiDataObject + +CLSS public org.netbeans.modules.jakarta.web.beans.CarCdiUtil +cons public init(org.netbeans.api.project.Project) +meth public java.util.Collection getBeansTargetFolder(boolean) +supr org.netbeans.modules.jakarta.web.beans.CdiUtil + +CLSS public org.netbeans.modules.jakarta.web.beans.CdiProjectOpenHook +cons public init(org.netbeans.api.project.Project) +meth protected void projectClosed() +meth protected void projectOpened() +supr org.netbeans.spi.project.ui.ProjectOpenedHook +hfds myProject + +CLSS public org.netbeans.modules.jakarta.web.beans.CdiUtil +cons public init(org.netbeans.api.project.Project) +fld public final static java.lang.String BEANS = "beans" +fld public final static java.lang.String BEANS_XML = "beans.xml" +fld public final static java.lang.String WEB_INF = "WEB-INF" +meth protected org.netbeans.api.project.Project getProject() +meth public boolean isCdi11OrLater() +meth public boolean isCdiEnabled() +meth public java.util.Collection getBeansTargetFolder(boolean) +meth public org.openide.filesystems.FileObject enableCdi() + anno 0 org.netbeans.api.annotations.common.CheckForNull() +meth public static boolean isCdi11OrLater(org.netbeans.api.project.Project) +meth public static boolean isCdiEnabled(org.netbeans.api.project.Project) +meth public static java.util.Collection getBeansTargetFolder(org.netbeans.api.project.Project,boolean) +meth public void log(java.lang.String,java.lang.Class,java.lang.Object[]) +meth public void log(java.lang.String,java.lang.Class,java.lang.Object[],boolean) +supr java.lang.Object +hfds LOG,META_INF,myMessages,myProject + +CLSS public org.netbeans.modules.jakarta.web.beans.EjbCdiUtil +cons public init(org.netbeans.api.project.Project) +meth public java.util.Collection getBeansTargetFolder(boolean) +supr org.netbeans.modules.jakarta.web.beans.CdiUtil + +CLSS public org.netbeans.modules.jakarta.web.beans.MetaModelSupport +cons public init(org.netbeans.api.project.Project) +meth public org.netbeans.api.java.classpath.ClassPath getClassPath(java.lang.String) +meth public org.netbeans.modules.j2ee.metadata.model.api.MetadataModel getMetaModel() +supr java.lang.Object +hfds MODELS,myProject + +CLSS public org.netbeans.modules.jakarta.web.beans.WebBeanInjectionTargetQueryImplementation +cons public init() +intf org.netbeans.modules.javaee.injection.spi.InjectionTargetQueryImplementation +meth public boolean isInjectionTarget(org.netbeans.api.java.source.CompilationController,javax.lang.model.element.TypeElement) +meth public boolean isStaticReferenceRequired(org.netbeans.api.java.source.CompilationController,javax.lang.model.element.TypeElement) +supr java.lang.Object + +CLSS public org.netbeans.modules.jakarta.web.beans.WebCdiUtil +cons public init(org.netbeans.api.project.Project) +meth public java.util.Collection getBeansTargetFolder(boolean) +supr org.netbeans.modules.jakarta.web.beans.CdiUtil + +CLSS public abstract org.netbeans.modules.jakarta.web.beans.api.model.AbstractModelImplementation +cons protected init(org.netbeans.modules.jakarta.web.beans.api.model.ModelUnit) +meth protected org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel getModel() +meth protected org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider getProvider() +meth public org.netbeans.modules.jakarta.web.beans.api.model.BeansModel getBeansModel() +meth public org.netbeans.modules.jakarta.web.beans.api.model.ModelUnit getModelUnit() +supr java.lang.Object +hfds myModel,myProvider,myUnit + +CLSS public final !enum org.netbeans.modules.jakarta.web.beans.api.model.BeanArchiveType +fld public final static org.netbeans.modules.jakarta.web.beans.api.model.BeanArchiveType EXPLICIT +fld public final static org.netbeans.modules.jakarta.web.beans.api.model.BeanArchiveType IMPLICIT +fld public final static org.netbeans.modules.jakarta.web.beans.api.model.BeanArchiveType NONE +meth public static org.netbeans.modules.jakarta.web.beans.api.model.BeanArchiveType valueOf(java.lang.String) +meth public static org.netbeans.modules.jakarta.web.beans.api.model.BeanArchiveType[] values() +supr java.lang.Enum + +CLSS public abstract interface org.netbeans.modules.jakarta.web.beans.api.model.BeansModel +meth public abstract boolean isCdi11OrLater() +meth public abstract java.util.LinkedHashSet getDecoratorClasses() +meth public abstract java.util.LinkedHashSet getInterceptorClasses() +meth public abstract java.util.Set getAlternativeClasses() +meth public abstract java.util.Set getAlternativeStereotypes() +meth public abstract org.netbeans.modules.jakarta.web.beans.api.model.BeanArchiveType getBeanArchiveType() + +CLSS public final org.netbeans.modules.jakarta.web.beans.api.model.BeansModelFactory +meth public static org.netbeans.modules.jakarta.web.beans.api.model.BeansModel createModel(org.netbeans.modules.jakarta.web.beans.api.model.ModelUnit) +meth public static org.netbeans.modules.jakarta.web.beans.api.model.BeansModel getModel(org.netbeans.modules.jakarta.web.beans.api.model.ModelUnit) +supr java.lang.Object +hfds MODELS + +CLSS public abstract interface org.netbeans.modules.jakarta.web.beans.api.model.BeansResult +meth public abstract boolean isDisabled(javax.lang.model.element.Element) + +CLSS public org.netbeans.modules.jakarta.web.beans.api.model.CdiException +cons public init(java.lang.String) +supr java.lang.Exception +hfds serialVersionUID + +CLSS public abstract interface org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult +innr public abstract interface static ApplicableResult +innr public abstract interface static Error +innr public abstract interface static InjectableResult +innr public abstract interface static ResolutionResult +innr public final static !enum ResultKind +meth public abstract javax.lang.model.element.VariableElement getVariable() +meth public abstract javax.lang.model.type.TypeMirror getVariableType() +meth public abstract org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult$ResultKind getKind() + +CLSS public abstract interface static org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult$ApplicableResult + outer org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult +intf org.netbeans.modules.jakarta.web.beans.api.model.BeansResult +intf org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult +meth public abstract java.util.Set getProductions() +meth public abstract java.util.Set getTypeElements() + +CLSS public abstract interface static org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult$Error + outer org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult +intf org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult +meth public abstract java.lang.String getMessage() + +CLSS public abstract interface static org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult$InjectableResult + outer org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult +intf org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult +meth public abstract javax.lang.model.element.Element getElement() + +CLSS public abstract interface static org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult$ResolutionResult + outer org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult +intf org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult +intf org.netbeans.modules.jakarta.web.beans.api.model.Result +meth public abstract boolean hasAlternative(javax.lang.model.element.Element) +meth public abstract boolean isAlternative(javax.lang.model.element.Element) + +CLSS public final static !enum org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult$ResultKind + outer org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult +fld public final static org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult$ResultKind DEFINITION_ERROR +fld public final static org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult$ResultKind INJECTABLES_RESOLVED +fld public final static org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult$ResultKind INJECTABLE_RESOLVED +fld public final static org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult$ResultKind RESOLUTION_ERROR +meth public static org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult$ResultKind valueOf(java.lang.String) +meth public static org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult$ResultKind[] values() +supr java.lang.Enum + +CLSS public org.netbeans.modules.jakarta.web.beans.api.model.InjectionPointDefinitionError +cons public init(javax.lang.model.element.Element,java.lang.String) +meth public javax.lang.model.element.Element getErrorElement() +supr org.netbeans.modules.jakarta.web.beans.api.model.CdiException +hfds myElement,serialVersionUID + +CLSS public abstract interface org.netbeans.modules.jakarta.web.beans.api.model.InterceptorsResult +intf org.netbeans.modules.jakarta.web.beans.api.model.BeansResult +intf org.netbeans.modules.jakarta.web.beans.api.model.Result +meth public abstract java.util.List getAllInterceptors() +meth public abstract java.util.List getDeclaredInterceptors() +meth public abstract java.util.List getResolvedInterceptors() +meth public abstract javax.lang.model.element.Element getElement() + +CLSS public org.netbeans.modules.jakarta.web.beans.api.model.ModelUnit +meth public boolean equals(java.lang.Object) +meth public int hashCode() +meth public org.netbeans.api.java.classpath.ClassPath getBootPath() +meth public org.netbeans.api.java.classpath.ClassPath getCompilePath() +meth public org.netbeans.api.java.classpath.ClassPath getSourcePath() +meth public org.netbeans.api.java.source.ClasspathInfo getClassPathInfo() +meth public org.netbeans.api.project.Project getProject() +meth public static org.netbeans.modules.jakarta.web.beans.api.model.ModelUnit create(org.netbeans.api.java.classpath.ClassPath,org.netbeans.api.java.classpath.ClassPath,org.netbeans.api.java.classpath.ClassPath,org.netbeans.api.project.Project) +supr java.lang.Object +hfds myBootPath,myClassPathInfo,myCompilePath,myProject,mySourcePath + +CLSS public abstract interface org.netbeans.modules.jakarta.web.beans.api.model.Result +meth public abstract java.util.List getAllStereotypes(javax.lang.model.element.Element) +meth public abstract java.util.List getStereotypes(javax.lang.model.element.Element) + +CLSS public final org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel +meth public boolean hasImplicitDefaultQualifier(javax.lang.model.element.Element) +meth public boolean isCdi11OrLater() +meth public boolean isDynamicInjectionPoint(javax.lang.model.element.VariableElement) +meth public boolean isEventInjectionPoint(javax.lang.model.element.VariableElement) +meth public boolean isInjectionPoint(javax.lang.model.element.VariableElement) throws org.netbeans.modules.jakarta.web.beans.api.model.InjectionPointDefinitionError +meth public java.lang.String getName(javax.lang.model.element.Element) +meth public java.lang.String getScope(javax.lang.model.element.Element) throws org.netbeans.modules.jakarta.web.beans.api.model.CdiException +meth public java.util.Collection getInterceptorBindings(javax.lang.model.element.Element) +meth public java.util.Collection getDecorators(javax.lang.model.element.TypeElement) +meth public java.util.List getQualifiers(javax.lang.model.element.Element,boolean) +meth public java.util.List getNamedElements() +meth public java.util.List getObservers(javax.lang.model.element.VariableElement,javax.lang.model.type.DeclaredType) +meth public java.util.List getEventInjectionPoints(javax.lang.model.element.ExecutableElement,javax.lang.model.type.DeclaredType) +meth public javax.lang.model.element.VariableElement getObserverParameter(javax.lang.model.element.ExecutableElement) +meth public javax.lang.model.type.TypeMirror resolveType(java.lang.String) +meth public org.netbeans.api.java.source.CompilationController getCompilationController() +meth public org.netbeans.modules.jakarta.web.beans.api.model.AbstractModelImplementation getModelImplementation() +meth public org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult lookupInjectables(javax.lang.model.element.VariableElement,javax.lang.model.type.DeclaredType,java.util.concurrent.atomic.AtomicBoolean) +meth public org.netbeans.modules.jakarta.web.beans.api.model.InterceptorsResult getInterceptors(javax.lang.model.element.Element) +supr java.lang.Object +hfds myImpl + +CLSS public final org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModelFactory +meth public static org.netbeans.modules.j2ee.metadata.model.api.MetadataModel createMetaModel(org.netbeans.modules.jakarta.web.beans.api.model.ModelUnit) +meth public static org.netbeans.modules.j2ee.metadata.model.api.MetadataModel getMetaModel(org.netbeans.modules.jakarta.web.beans.api.model.ModelUnit) +supr java.lang.Object +hfds MODELS + +CLSS public abstract interface org.netbeans.modules.javaee.injection.spi.InjectionTargetQueryImplementation +meth public abstract boolean isInjectionTarget(org.netbeans.api.java.source.CompilationController,javax.lang.model.element.TypeElement) +meth public abstract boolean isStaticReferenceRequired(org.netbeans.api.java.source.CompilationController,javax.lang.model.element.TypeElement) + +CLSS public abstract org.netbeans.spi.project.ui.ProjectOpenedHook +cons protected init() +meth protected abstract void projectClosed() +meth protected abstract void projectOpened() +supr java.lang.Object + +CLSS public abstract org.openide.loaders.DataObject +cons public init(org.openide.filesystems.FileObject,org.openide.loaders.DataLoader) throws org.openide.loaders.DataObjectExistsException +fld public final static java.lang.String PROP_COOKIE = "cookie" +fld public final static java.lang.String PROP_FILES = "files" +fld public final static java.lang.String PROP_HELP = "helpCtx" +fld public final static java.lang.String PROP_MODIFIED = "modified" +fld public final static java.lang.String PROP_NAME = "name" +fld public final static java.lang.String PROP_PRIMARY_FILE = "primaryFile" +fld public final static java.lang.String PROP_TEMPLATE = "template" +fld public final static java.lang.String PROP_VALID = "valid" +innr public abstract interface static !annotation Registration +innr public abstract interface static !annotation Registrations +innr public abstract interface static Container +innr public abstract interface static Factory +innr public final static Registry +intf java.io.Serializable +intf org.openide.nodes.Node$Cookie +intf org.openide.util.HelpCtx$Provider +intf org.openide.util.Lookup$Provider +meth protected <%0 extends org.openide.nodes.Node$Cookie> {%%0} getCookie(org.openide.loaders.DataShadow,java.lang.Class<{%%0}>) +meth protected abstract org.openide.filesystems.FileObject handleMove(org.openide.loaders.DataFolder) throws java.io.IOException +meth protected abstract org.openide.filesystems.FileObject handleRename(java.lang.String) throws java.io.IOException +meth protected abstract org.openide.loaders.DataObject handleCopy(org.openide.loaders.DataFolder) throws java.io.IOException +meth protected abstract org.openide.loaders.DataObject handleCreateFromTemplate(org.openide.loaders.DataFolder,java.lang.String) throws java.io.IOException +meth protected abstract void handleDelete() throws java.io.IOException +meth protected final void firePropertyChange(java.lang.String,java.lang.Object,java.lang.Object) +meth protected final void fireVetoableChange(java.lang.String,java.lang.Object,java.lang.Object) throws java.beans.PropertyVetoException +meth protected final void markFiles() throws java.io.IOException +meth protected org.openide.filesystems.FileLock takePrimaryFileLock() throws java.io.IOException +meth protected org.openide.loaders.DataObject handleCopyRename(org.openide.loaders.DataFolder,java.lang.String,java.lang.String) throws java.io.IOException +meth protected org.openide.loaders.DataShadow handleCreateShadow(org.openide.loaders.DataFolder) throws java.io.IOException +meth protected org.openide.nodes.Node createNodeDelegate() +meth protected void dispose() +meth public <%0 extends org.openide.nodes.Node$Cookie> {%%0} getCookie(java.lang.Class<{%%0}>) +meth public abstract boolean isCopyAllowed() +meth public abstract boolean isDeleteAllowed() +meth public abstract boolean isMoveAllowed() +meth public abstract boolean isRenameAllowed() +meth public abstract org.openide.util.HelpCtx getHelpCtx() +meth public boolean isModified() +meth public boolean isShadowAllowed() +meth public final boolean isTemplate() +meth public final boolean isValid() +meth public final org.openide.filesystems.FileObject getPrimaryFile() +meth public final org.openide.loaders.DataFolder getFolder() +meth public final org.openide.loaders.DataLoader getLoader() +meth public final org.openide.loaders.DataObject copy(org.openide.loaders.DataFolder) throws java.io.IOException +meth public final org.openide.loaders.DataObject createFromTemplate(org.openide.loaders.DataFolder) throws java.io.IOException +meth public final org.openide.loaders.DataObject createFromTemplate(org.openide.loaders.DataFolder,java.lang.String) throws java.io.IOException +meth public final org.openide.loaders.DataObject createFromTemplate(org.openide.loaders.DataFolder,java.lang.String,java.util.Map) throws java.io.IOException +meth public final org.openide.loaders.DataShadow createShadow(org.openide.loaders.DataFolder) throws java.io.IOException +meth public final org.openide.nodes.Node getNodeDelegate() +meth public final void delete() throws java.io.IOException +meth public final void move(org.openide.loaders.DataFolder) throws java.io.IOException +meth public final void rename(java.lang.String) throws java.io.IOException +meth public final void setTemplate(boolean) throws java.io.IOException +meth public java.lang.Object writeReplace() +meth public java.lang.String getName() +meth public java.lang.String toString() +meth public java.util.Set files() +meth public org.openide.util.Lookup getLookup() +meth public static org.openide.loaders.DataObject find(org.openide.filesystems.FileObject) throws org.openide.loaders.DataObjectNotFoundException +meth public static org.openide.loaders.DataObject$Registry getRegistry() +meth public void addPropertyChangeListener(java.beans.PropertyChangeListener) +meth public void addVetoableChangeListener(java.beans.VetoableChangeListener) +meth public void removePropertyChangeListener(java.beans.PropertyChangeListener) +meth public void removeVetoableChangeListener(java.beans.VetoableChangeListener) +meth public void setModified(boolean) +meth public void setValid(boolean) throws java.beans.PropertyVetoException +supr java.lang.Object +hfds BEING_CREATED,EA_ASSIGNED_LOADER,EA_ASSIGNED_LOADER_MODULE,LOCK,LOG,OBJ_LOG,PROGRESS_INFO_TL,REGISTRY_INSTANCE,changeSupport,changeSupportUpdater,item,loader,modif,modified,nodeDelegate,serialVersionUID,syncModified,synchObject,vetoableChangeSupport,warnedClasses +hcls CreateAction,DOSavable,ModifiedRegistry,ProgressInfo,Replace + +CLSS public org.openide.loaders.MultiDataObject +cons public init(org.openide.filesystems.FileObject,org.openide.loaders.MultiFileLoader) throws org.openide.loaders.DataObjectExistsException +innr public abstract Entry +meth protected final org.openide.loaders.MultiDataObject$Entry registerEntry(org.openide.filesystems.FileObject) +meth protected final org.openide.nodes.CookieSet getCookieSet() +meth protected final void addSecondaryEntry(org.openide.loaders.MultiDataObject$Entry) +meth protected final void registerEditor(java.lang.String,boolean) +meth protected final void removeSecondaryEntry(org.openide.loaders.MultiDataObject$Entry) +meth protected final void setCookieSet(org.openide.nodes.CookieSet) + anno 0 java.lang.Deprecated() +meth protected int associateLookup() +meth protected org.openide.filesystems.FileLock takePrimaryFileLock() throws java.io.IOException +meth protected org.openide.filesystems.FileObject handleMove(org.openide.loaders.DataFolder) throws java.io.IOException +meth protected org.openide.filesystems.FileObject handleRename(java.lang.String) throws java.io.IOException +meth protected org.openide.loaders.DataObject handleCopy(org.openide.loaders.DataFolder) throws java.io.IOException +meth protected org.openide.loaders.DataObject handleCopyRename(org.openide.loaders.DataFolder,java.lang.String,java.lang.String) throws java.io.IOException +meth protected org.openide.loaders.DataObject handleCreateFromTemplate(org.openide.loaders.DataFolder,java.lang.String) throws java.io.IOException +meth protected org.openide.nodes.Node createNodeDelegate() +meth protected void handleDelete() throws java.io.IOException +meth public <%0 extends org.openide.nodes.Node$Cookie> {%%0} getCookie(java.lang.Class<{%%0}>) +meth public boolean isCopyAllowed() +meth public boolean isDeleteAllowed() +meth public boolean isMoveAllowed() +meth public boolean isRenameAllowed() +meth public final java.util.Set secondaryEntries() +meth public final org.openide.loaders.MultiDataObject$Entry findSecondaryEntry(org.openide.filesystems.FileObject) +meth public final org.openide.loaders.MultiDataObject$Entry getPrimaryEntry() +meth public final org.openide.loaders.MultiFileLoader getMultiFileLoader() +meth public java.util.Set files() +meth public org.openide.util.HelpCtx getHelpCtx() +meth public org.openide.util.Lookup getLookup() +supr org.openide.loaders.DataObject +hfds ERR,RECOGNIZER,TEMPLATE_ATTRIBUTES,chLis,checked,cookieSet,cookieSetLock,delayProcessor,delayedPropFilesLock,delayedPropFilesTask,firingProcessor,later,primary,secondary,secondaryCreationLock,serialVersionUID +hcls ChangeAndBefore,EmptyRecognizer,EntryReplace,Pair + +CLSS public abstract org.openide.nodes.Node +cons protected init(org.openide.nodes.Children) +cons protected init(org.openide.nodes.Children,org.openide.util.Lookup) +fld public final static java.lang.String PROP_COOKIE = "cookie" +fld public final static java.lang.String PROP_DISPLAY_NAME = "displayName" +fld public final static java.lang.String PROP_ICON = "icon" +fld public final static java.lang.String PROP_LEAF = "leaf" +fld public final static java.lang.String PROP_NAME = "name" +fld public final static java.lang.String PROP_OPENED_ICON = "openedIcon" +fld public final static java.lang.String PROP_PARENT_NODE = "parentNode" +fld public final static java.lang.String PROP_PROPERTY_SETS = "propertySets" +fld public final static java.lang.String PROP_SHORT_DESCRIPTION = "shortDescription" +fld public final static org.openide.nodes.Node EMPTY +innr public abstract interface static Cookie +innr public abstract interface static Handle +innr public abstract static IndexedProperty +innr public abstract static Property +innr public abstract static PropertySet +intf org.openide.util.HelpCtx$Provider +intf org.openide.util.Lookup$Provider +meth protected final boolean hasPropertyChangeListener() +meth protected final void fireCookieChange() +meth protected final void fireDisplayNameChange(java.lang.String,java.lang.String) +meth protected final void fireIconChange() +meth protected final void fireNameChange(java.lang.String,java.lang.String) +meth protected final void fireNodeDestroyed() +meth protected final void fireOpenedIconChange() +meth protected final void firePropertyChange(java.lang.String,java.lang.Object,java.lang.Object) +meth protected final void firePropertySetsChange(org.openide.nodes.Node$PropertySet[],org.openide.nodes.Node$PropertySet[]) +meth protected final void fireShortDescriptionChange(java.lang.String,java.lang.String) +meth protected final void setChildren(org.openide.nodes.Children) +meth protected java.lang.Object clone() throws java.lang.CloneNotSupportedException +meth public <%0 extends org.openide.nodes.Node$Cookie> {%%0} getCookie(java.lang.Class<{%%0}>) +meth public abstract boolean canCopy() +meth public abstract boolean canCut() +meth public abstract boolean canDestroy() +meth public abstract boolean canRename() +meth public abstract boolean hasCustomizer() +meth public abstract java.awt.Component getCustomizer() +meth public abstract java.awt.Image getIcon(int) +meth public abstract java.awt.Image getOpenedIcon(int) +meth public abstract java.awt.datatransfer.Transferable clipboardCopy() throws java.io.IOException +meth public abstract java.awt.datatransfer.Transferable clipboardCut() throws java.io.IOException +meth public abstract java.awt.datatransfer.Transferable drag() throws java.io.IOException +meth public abstract org.openide.nodes.Node cloneNode() +meth public abstract org.openide.nodes.Node$Handle getHandle() +meth public abstract org.openide.nodes.Node$PropertySet[] getPropertySets() +meth public abstract org.openide.util.HelpCtx getHelpCtx() +meth public abstract org.openide.util.datatransfer.NewType[] getNewTypes() +meth public abstract org.openide.util.datatransfer.PasteType getDropType(java.awt.datatransfer.Transferable,int,int) +meth public abstract org.openide.util.datatransfer.PasteType[] getPasteTypes(java.awt.datatransfer.Transferable) +meth public boolean equals(java.lang.Object) +meth public final boolean isLeaf() +meth public final javax.swing.JPopupMenu getContextMenu() +meth public final org.openide.nodes.Children getChildren() +meth public final org.openide.nodes.Node getParentNode() +meth public final org.openide.util.Lookup getLookup() +meth public final void addNodeListener(org.openide.nodes.NodeListener) +meth public final void addPropertyChangeListener(java.beans.PropertyChangeListener) +meth public final void removeNodeListener(org.openide.nodes.NodeListener) +meth public final void removePropertyChangeListener(java.beans.PropertyChangeListener) +meth public int hashCode() +meth public java.lang.String getHtmlDisplayName() +meth public java.lang.String toString() +meth public javax.swing.Action getPreferredAction() +meth public javax.swing.Action[] getActions(boolean) +meth public org.openide.util.actions.SystemAction getDefaultAction() + anno 0 java.lang.Deprecated() +meth public org.openide.util.actions.SystemAction[] getActions() + anno 0 java.lang.Deprecated() +meth public org.openide.util.actions.SystemAction[] getContextActions() + anno 0 java.lang.Deprecated() +meth public void destroy() throws java.io.IOException +meth public void setDisplayName(java.lang.String) +meth public void setHidden(boolean) + anno 0 java.lang.Deprecated() +meth public void setName(java.lang.String) +meth public void setShortDescription(java.lang.String) +supr java.beans.FeatureDescriptor +hfds BLOCK_EVENTS,INIT_LOCK,LOCK,TEMPL_COOKIE,err,hierarchy,listeners,lookups,parent,warnedBadProperties +hcls LookupEventList,PropertyEditorRef + +CLSS public abstract interface static org.openide.nodes.Node$Cookie + outer org.openide.nodes.Node + +CLSS public final org.openide.util.HelpCtx +cons public init(java.lang.Class) + anno 0 java.lang.Deprecated() +cons public init(java.lang.String) +cons public init(java.net.URL) + anno 0 java.lang.Deprecated() +fld public final static org.openide.util.HelpCtx DEFAULT_HELP +innr public abstract interface static Displayer +innr public abstract interface static Provider +meth public boolean display() +meth public boolean equals(java.lang.Object) +meth public int hashCode() +meth public java.lang.String getHelpID() +meth public java.lang.String toString() +meth public java.net.URL getHelp() +meth public static org.openide.util.HelpCtx findHelp(java.awt.Component) +meth public static org.openide.util.HelpCtx findHelp(java.lang.Object) +meth public static void setHelpIDString(javax.swing.JComponent,java.lang.String) +supr java.lang.Object +hfds err,helpCtx,helpID + +CLSS public abstract interface static org.openide.util.HelpCtx$Provider + outer org.openide.util.HelpCtx +meth public abstract org.openide.util.HelpCtx getHelpCtx() + +CLSS public abstract org.openide.util.Lookup +cons public init() +fld public final static org.openide.util.Lookup EMPTY +innr public abstract interface static Provider +innr public abstract static Item +innr public abstract static Result +innr public final static Template +meth public <%0 extends java.lang.Object> java.util.Collection lookupAll(java.lang.Class<{%%0}>) +meth public <%0 extends java.lang.Object> org.openide.util.Lookup$Item<{%%0}> lookupItem(org.openide.util.Lookup$Template<{%%0}>) +meth public <%0 extends java.lang.Object> org.openide.util.Lookup$Result<{%%0}> lookupResult(java.lang.Class<{%%0}>) +meth public abstract <%0 extends java.lang.Object> org.openide.util.Lookup$Result<{%%0}> lookup(org.openide.util.Lookup$Template<{%%0}>) +meth public abstract <%0 extends java.lang.Object> {%%0} lookup(java.lang.Class<{%%0}>) +meth public static org.openide.util.Lookup getDefault() +supr java.lang.Object +hfds LOG,defaultLookup,defaultLookupProvider +hcls DefLookup,Empty + +CLSS public abstract interface static org.openide.util.Lookup$Provider + outer org.openide.util.Lookup +meth public abstract org.openide.util.Lookup getLookup() + diff --git a/enterprise/jakarta.web.beans/nbproject/project.properties b/enterprise/jakarta.web.beans/nbproject/project.properties new file mode 100644 index 000000000000..ea59ff1cb5d3 --- /dev/null +++ b/enterprise/jakarta.web.beans/nbproject/project.properties @@ -0,0 +1,27 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +javac.compilerargs=-Xlint -Xlint:-serial +javac.source=1.8 +nbm.module.author=Josh Juneau +requires.nb.javac=true + +test-unit-sys-prop.java.awt.headless=true +test.config.stable.includes=\ +**/*Test.class +test.config.stableBTD.includes=\ + **/xdm/model/*Test.class diff --git a/enterprise/jakarta.web.beans/nbproject/project.xml b/enterprise/jakarta.web.beans/nbproject/project.xml new file mode 100644 index 000000000000..87cc689e8318 --- /dev/null +++ b/enterprise/jakarta.web.beans/nbproject/project.xml @@ -0,0 +1,481 @@ + + + + org.netbeans.modules.apisupport.project + + + org.netbeans.modules.jakarta.web.beans + + + org.netbeans.api.annotations.common + + + + 1 + 1.17 + + + + org.netbeans.api.java.classpath + + + + 1 + 1.20 + + + + org.netbeans.api.web.webmodule + + + + 1.0 + + + + org.netbeans.libs.javacapi + + + + 0.5 + + + + org.netbeans.modules.editor + + + + 3 + 1.53 + + + + org.netbeans.modules.editor.completion + + + + 1 + 1.38 + + + + org.netbeans.modules.editor.document + + + + 1.3 + + + + org.netbeans.modules.editor.lib + + + + 3 + 4.0 + + + + org.netbeans.modules.editor.lib2 + + + + 1 + 2.0 + + + + org.netbeans.modules.editor.mimelookup + + + + 1 + 1.34 + + + + org.netbeans.modules.j2ee.api.ejbmodule + + + + 1.15 + + + + org.netbeans.modules.j2ee.common + + + + 1 + 1.86 + + + + org.netbeans.modules.j2ee.core + + + + 0-1 + 1.1 + + + + org.netbeans.modules.j2ee.metadata + + + + 0-1 + 1.7 + + + + org.netbeans.modules.j2ee.metadata.model.support + + + + 1 + 1.14 + + + + org.netbeans.modules.java.hints.legacy.spi + + + + 1 + 1.0 + + + + org.netbeans.modules.java.lexer + + + + 1 + 1.11 + + + + org.netbeans.modules.java.project + + + + 1 + 1.62 + + + + org.netbeans.modules.java.source + + + + 0.141 + + + + org.netbeans.modules.java.source.base + + + + 1.0 + + + + org.netbeans.modules.java.sourceui + + + + 1 + 1.8 + + + + org.netbeans.modules.javaee.injection + + + + 1.0 + + + + org.netbeans.modules.lexer + + + + 2 + 1.36 + + + + org.netbeans.modules.libs.corba.omgapi + + + + 1.0 + + + + org.netbeans.modules.parsing.api + + + + 1 + 9.0 + + + + org.netbeans.modules.projectapi + + + + 1 + + + + org.netbeans.modules.projectuiapi + + + + 1 + 1.78 + + + + org.netbeans.modules.projectuiapi.base + + + + 1 + 1.78 + + + + org.netbeans.modules.xml.lexer + + + + 1.30 + + + + org.netbeans.modules.xml.retriever + + + + 1 + 1.1 + + + + org.netbeans.modules.xml.text + + + + 2 + 1.60 + + + + org.netbeans.modules.xml.xam + + + + 1 + 1.6 + + + + org.netbeans.spi.editor.hints + + + + 0-1 + 1.15 + + + + org.openide.awt + + + + 7.11 + + + + org.openide.dialogs + + + + 7.14 + + + + org.openide.filesystems + + + + 9.0 + + + + org.openide.loaders + + + + 7.61 + + + + org.openide.nodes + + + + 7.13 + + + + org.openide.text + + + + 6.40 + + + + org.openide.util + + + + 9.3 + + + + org.openide.util.lookup + + + + 8.0 + + + + org.openide.util.ui + + + + 9.3 + + + + org.openide.windows + + + + 6.28 + + + + + + + unit + + org.netbeans.libs.junit4 + + + + org.netbeans.modules.csl.api + + + + org.netbeans.modules.editor.mimelookup.impl + + + org.netbeans.modules.j2ee.dd + + + + + org.netbeans.modules.j2ee.metadata.model.support + + + + + org.netbeans.modules.javahelp + + + + + org.netbeans.modules.masterfs + + + org.netbeans.modules.nbjunit + + + + + org.netbeans.modules.parsing.nb + + + org.netbeans.modules.projectapi.nb + + + org.netbeans.modules.projectui + + + org.netbeans.modules.xml.retriever + + + + org.netbeans.modules.xml.text + + + + org.netbeans.modules.xml.xdm + + + + org.openide.text + + + org.openide.util.ui + + + + + org.openide.util.lookup + + + + + + + org.netbeans.modules.j2ee.ejbcore + org.netbeans.modules.web.el + org.netbeans.modules.web.jsf + org.netbeans.modules.web.jsf.editor + org.netbeans.gradle.javaee.project + org.netbeans.modules.jakarta.web.beans + org.netbeans.modules.jakarta.web.beans.api.model + + + + diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/BeansDataLoader.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/BeansDataLoader.java new file mode 100644 index 000000000000..d415a39dddd4 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/BeansDataLoader.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//package org.netbeans.modules.jakarta.web.beans; +// +//import java.io.IOException; +//import org.openide.filesystems.FileObject; +//import org.openide.loaders.DataLoader; +//import org.openide.loaders.DataObject; +//import org.openide.util.NbBundle; +// +///** +// */ +//public class BeansDataLoader extends DataLoader { +// +// public static final String REQUIRED_MIME = "text/x-beans-jakarta+xml"; +// +// public BeansDataLoader() { +// super(BeansDataObject.class.getName()); +// } +// +// @Override +// protected void initialize() { +// super.initialize(); +// } +// +// @Override +// protected String defaultDisplayName() { +// return NbBundle.getMessage(BeansDataLoader.class, "LBL_loaderName"); // NOI18N +// } +// +// @Override +// protected String actionsContext() { +// return "Loaders/" + REQUIRED_MIME + "/Actions"; +// } +// +// @Override +// protected DataObject handleFindDataObject(FileObject fo, RecognizedFiles recognized) throws IOException { +// return new BeansDataObject(fo, this); +// } +//} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/BeansDataObject.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/BeansDataObject.java new file mode 100644 index 000000000000..995e71be9d1c --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/BeansDataObject.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans; + +import java.io.IOException; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionReferences; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.MIMEResolver; +import org.openide.loaders.DataObject; +import org.openide.loaders.DataObjectExistsException; +import org.openide.loaders.MultiDataObject; +import org.openide.loaders.MultiFileLoader; +import org.openide.util.Lookup; +import org.openide.util.NbBundle.Messages; +import org.openide.windows.TopComponent; + +@Messages({ + "LBL_Beans_LOADER_JAKARTA=Files of Beans" +}) +@MIMEResolver.NamespaceRegistration( + displayName = "#LBL_Beans_LOADER_JAKARTA", + mimeType = "text/x-beans-jakarta+xml", + elementNS = {"https://jakarta.ee/xml/ns/jakartaee"}, + position = 819 +) +@DataObject.Registration( + mimeType = "text/x-beans-jakarta+xml", + iconBase = "org/netbeans/modules/jakarta/web/beans/resources/delegate.png", + displayName = "#LBL_Beans_LOADER_JAKARTA" +) +@ActionReferences({ + @ActionReference( + path = "Loaders/text/x-beans-jakarta+xml/Actions", + id = @ActionID(category = "System", id = "org.openide.actions.OpenAction"), + position = 100, + separatorAfter = 200 + ), + @ActionReference( + path = "Loaders/text/x-beans-jakarta+xml/Actions", + id = @ActionID(category = "Edit", id = "org.openide.actions.CutAction"), + position = 300 + ), + @ActionReference( + path = "Loaders/text/x-beans-jakarta+xml/Actions", + id = @ActionID(category = "Edit", id = "org.openide.actions.CopyAction"), + position = 400, + separatorAfter = 500 + ), + @ActionReference( + path = "Loaders/text/x-beans-jakarta+xml/Actions", + id = @ActionID(category = "Edit", id = "org.openide.actions.DeleteAction"), + position = 600 + ), + @ActionReference( + path = "Loaders/text/x-beans-jakarta+xml/Actions", + id = @ActionID(category = "System", id = "org.openide.actions.RenameAction"), + position = 700, + separatorAfter = 800 + ), + @ActionReference( + path = "Loaders/text/x-beans-jakarta+xml/Actions", + id = @ActionID(category = "System", id = "org.openide.actions.SaveAsTemplateAction"), + position = 900, + separatorAfter = 1000 + ), + @ActionReference( + path = "Loaders/text/x-beans-jakarta+xml/Actions", + id = @ActionID(category = "System", id = "org.openide.actions.FileSystemAction"), + position = 1100, + separatorAfter = 1200 + ), + @ActionReference( + path = "Loaders/text/x-beans-jakarta+xml/Actions", + id = @ActionID(category = "System", id = "org.openide.actions.ToolsAction"), + position = 1300 + ), + @ActionReference( + path = "Loaders/text/x-beans-jakarta+xml/Actions", + id = @ActionID(category = "System", id = "org.openide.actions.PropertiesAction"), + position = 1400 + ) +}) +public class BeansDataObject extends MultiDataObject { + + public BeansDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException { + super(pf, loader); + registerEditor("text/x-beans-jakarta+xml", false); + } + + @Override + protected int associateLookup() { + return 1; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/Bundle.properties b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/Bundle.properties new file mode 100644 index 000000000000..19b03cffa460 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/Bundle.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +USG_CDI_BEANS_OPENED_PROJECT=Opened Project "{0}" with existing beans.xml file. \ No newline at end of file diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/CarCdiUtil.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/CarCdiUtil.java new file mode 100644 index 000000000000..2195f29d3454 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/CarCdiUtil.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans; + +import java.util.Collection; +import java.util.Collections; + +import org.netbeans.api.project.Project; +import org.netbeans.modules.j2ee.api.ejbjar.Car; +import org.netbeans.spi.project.ProjectServiceProvider; +import org.netbeans.spi.project.ui.ProjectOpenedHook; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +@ProjectServiceProvider(service=CdiUtil.class, projectType = { + "org-netbeans-modules-j2ee-clientproject","org-netbeans-modules-maven/app-client"}) +public class CarCdiUtil extends CdiUtil { + + public CarCdiUtil( Project project ) { + super(project); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.CdiUtil#getBeansTargetFolder(boolean) + */ + @Override + public Collection getBeansTargetFolder( boolean create ) { + Project project = getProject(); + if ( project == null ){ + return Collections.emptyList(); + } + Car cars[] = Car.getCars(project); + if (cars.length > 0) { + return Collections.singleton(cars[0].getMetaInf()); + } + return super.getBeansTargetFolder(create); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/CdiProjectOpenHook.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/CdiProjectOpenHook.java new file mode 100644 index 000000000000..873f6b89d025 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/CdiProjectOpenHook.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans; + +import java.lang.ref.WeakReference; + +import org.netbeans.api.project.Project; +import org.netbeans.spi.project.ProjectServiceProvider; +import org.netbeans.spi.project.ui.ProjectOpenedHook; + + +/** + * @author ads + * + */ +@ProjectServiceProvider(service={ProjectOpenedHook.class}, projectType = { + "org-netbeans-modules-java-j2seproject", + "org-netbeans-modules-j2ee-clientproject", + "org-netbeans-modules-j2ee-ejbjarproject", + "org-netbeans-modules-web-project", + "org-netbeans-modules-maven/jar", + "org-netbeans-modules-maven/war", + "org-netbeans-modules-maven/ejb", + "org-netbeans-modules-maven/app-client"} + ) +public class CdiProjectOpenHook extends ProjectOpenedHook { + + public CdiProjectOpenHook(Project project){ + myProject = new WeakReference( project ); + } + + /* (non-Javadoc) + * @see org.netbeans.spi.project.ui.ProjectOpenedHook#projectClosed() + */ + @Override + protected void projectClosed() { + } + + /* (non-Javadoc) + * @see org.netbeans.spi.project.ui.ProjectOpenedHook#projectOpened() + */ + @Override + protected void projectOpened() { + Project project = myProject.get(); + if ( project == null ){ + return; + } + CdiUtil util = project.getLookup().lookup(CdiUtil.class); + if ( util!= null && util.isCdiEnabled() ){ + util.log("USG_CDI_BEANS_OPENED_PROJECT", CdiProjectOpenHook.class, + new Object[]{project.getClass().getName()}); // NOI18N + } + } + + private WeakReference myProject; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/CdiUtil.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/CdiUtil.java new file mode 100644 index 000000000000..e71c949e1cc7 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/CdiUtil.java @@ -0,0 +1,330 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans; + +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import org.netbeans.api.annotations.common.CheckForNull; +import org.netbeans.api.j2ee.core.Profile; +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.java.project.JavaProjectConstants; + +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectUtils; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.api.project.SourceGroupModifier; +import org.netbeans.api.project.Sources; +import org.netbeans.modules.j2ee.api.ejbjar.EjbJar; +import org.netbeans.modules.j2ee.common.dd.DDHelper; +import org.netbeans.modules.jakarta.web.beans.xml.BeansAttributes; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansModelFactory; +import org.netbeans.modules.xml.retriever.catalog.Utilities; +import org.netbeans.modules.xml.xam.ModelSource; +import org.netbeans.modules.xml.xam.locator.CatalogModelException; +import org.netbeans.spi.project.ProjectServiceProvider; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.util.Exceptions; +import org.openide.util.NbBundle; + + +/** + * @author ads + * beware, non-static methods may behave differently in different projects(by type) if provider is overrided and registred to appropriate project type + * known subclasses #WebCdiUtil + */ +@ProjectServiceProvider(service=CdiUtil.class, projectType = { + "org-netbeans-modules-java-j2seproject", "org-netbeans-modules-maven/jar"}) +public class CdiUtil { + + private static final Logger LOG = Logger.getLogger("org.netbeans.ui.metrics.cdi"); // NOI18N + + public static final String BEANS = "beans"; // NOI18N + public static final String BEANS_XML = BEANS+".xml"; // NOI18N + private static final String META_INF = "META-INF"; // NOI18N + public static final String WEB_INF = "WEB-INF"; // NOI18N + + public CdiUtil(Project project){ + myProject = new WeakReference<>( project ); + myMessages = new CopyOnWriteArraySet<>(); + } + + public void log(String message , Class clazz, Object[] params){ + log(message, clazz, params , false ); + } + + + public void log(String message , Class clazz, Object[] params, boolean once){ + if (!once) { + if (myMessages.contains(message)) { + return; + } + else { + myMessages.add(message); + } + } + + LogRecord logRecord = new LogRecord(Level.INFO, message); + logRecord.setLoggerName(LOG.getName()); + logRecord.setResourceBundle(NbBundle.getBundle(clazz)); + logRecord.setResourceBundleName(clazz.getPackage().getName() + ".Bundle"); // NOI18N + if (params != null) { + logRecord.setParameters(params); + } + LOG.log(logRecord); + } + + /** + * check if cdi is enabled in supplied project, general implementation + * @param project + * @return + */ + public static boolean isCdiEnabled(Project project){ + return (getBeansXmlExists(project)!=null) || isCdi11OrLater(project); + } + + private static FileObject getBeansXmlExists(Project project){ + Collection beansTargetFolder = getBeansTargetFolder(project, false); + for (FileObject fileObject : beansTargetFolder) { + if ( fileObject != null && fileObject.getFileObject(BEANS_XML)!=null){ + return fileObject.getFileObject(BEANS_XML); + } + } + return null; + } + + private FileObject getBeansXmlExists(){ + Collection beansTargetFolder = getBeansTargetFolder(false); + for (FileObject fileObject : beansTargetFolder) { + if ( fileObject != null && fileObject.getFileObject(BEANS_XML)!=null){ + return fileObject.getFileObject(BEANS_XML); + } + } + return null; + } + + /** + * check if cdi is enabled in the project where CdiUtil is registered as a service + * @return ch + */ + public boolean isCdiEnabled(){ + Project project = getProject(); + if ( project == null ){ + return false; + } + Collection beansTargetFolder = getBeansTargetFolder(false); + for (FileObject fileObject : beansTargetFolder) { + if ( fileObject != null && fileObject.getFileObject(BEANS_XML)!=null){ + return true; + } + } + // #229078 - since CDI 1.1 beans.xml is optional in case of 'implicit bean archive' + if (isCdi11OrLater()) { + return true; + } + return false; + } + + /** + * Avoid static methods usage as much as possible, use isCdi11OrLater() instead + * @param p + * @return + */ + public static boolean isCdi11OrLater(Project p) { + if(! hasResource(p, "javax/enterprise/inject/spi/AfterTypeDiscovery.class") ) { + return false; + } else { + FileObject beans = getBeansXmlExists(p); + if(beans == null) { + return true;//no beans.xml and ee7 environment, default cdi 1.1 behavior + } + WebBeansModel model = WebBeansModelFactory.getInstance().getModel(getModelSource(beans, true)); + if (model == null) { + return false;//??? + } + + String attribute = model.getRootComponent().getAttribute(BeansAttributes.VERSION); + if(attribute == null || attribute.equals("1.0")) { + return false;//no version attribute in cdi1.0 or equal to "1.0" in cdi 1.1. + } + return true; + } + } + + public boolean isCdi11OrLater() { + if(! hasResource(getProject(), "javax/enterprise/inject/spi/AfterTypeDiscovery.class") ) { + return false; + } else { + FileObject beans = getBeansXmlExists(); + if(beans == null) { + return true;//no beans.xml and ee7 environment, default cdi 1.1 behavior + } + WebBeansModel model = WebBeansModelFactory.getInstance().getModel(getModelSource(beans, true)); + if (model == null || model.getRootComponent() == null) { + return false;//empty? as in cdi1.0 + } + + String attribute = model.getRootComponent().getAttribute(BeansAttributes.XMLNS); + String version = model.getRootComponent().getAttribute(BeansAttributes.VERSION); + if(attribute != null && attribute.startsWith("http://java")) {//NOI18N + return false;//only cdi1.0 use java.sun.com namespace, also default for future usage is cdi 1.1 (in case of corrupted beans without namespace) + } else if ("1.0".equals(version)){//NOI18N + return false;//we can fall back with version attribute if exists. + } + return true; + } + } + + private static ModelSource getModelSource( FileObject fileObject , + boolean isEditable ) + { + try { + return Utilities.createModelSource( fileObject,isEditable); + } catch (CatalogModelException ex) { + Logger.getLogger("global").log(java.util.logging.Level.SEVERE, + ex.getMessage(), ex); // NOI18N + } + return null; + } + + private static boolean hasResource(Project project, String resource) { + SourceGroup[] sgs = ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA); + if (sgs.length < 1) { + return false; + } + FileObject sourceRoot = sgs[0].getRootFolder(); + ClassPath classPath = ClassPath.getClassPath(sourceRoot, ClassPath.COMPILE); + if (classPath == null) { + return false; + } + FileObject resourceFile = classPath.findResource(resource); + if (resourceFile != null) { + return true; + } + return false; + } + + public Collection getBeansTargetFolder(boolean create) + { + Project project = getProject(); + if ( project == null ){ + return Collections.emptyList(); + } + return getBeansTargetFolder(project, create); + } + + protected Project getProject(){ + return myProject.get(); + } + + /** + * Enables CDI in the project and returns reference to the created beans.xml file if any. + * @return reference to beans.xml if was created, {@code null} otherwise + * @since 2.3 + */ + @CheckForNull + public FileObject enableCdi() { + Collection infs = getBeansTargetFolder(true); + for (FileObject inf : infs) { + if (inf != null) { + FileObject beansXml = inf.getFileObject(CdiUtil.BEANS_XML); + if (beansXml != null) { + return null; + } + try { + EjbJar ejbJar = EjbJar.getEjbJar(myProject.get().getProjectDirectory()); + Profile profile = ejbJar != null ? ejbJar.getJ2eeProfile() : Profile.JAVA_EE_6_WEB; + LOG.log(Level.INFO, "Creating beans.xml file for project: {0}", myProject.get().getProjectDirectory()); + return DDHelper.createBeansXml(profile, inf, CdiUtil.BEANS); + } catch (IOException exception) { + Exceptions.printStackTrace(exception); + } + return null; + } + } + return null; + } + + public static Collection getBeansTargetFolder(Project project, + boolean create) + { + Sources sources = ProjectUtils.getSources(project); + Collection result = new ArrayList<>(2); + SourceGroup[] sourceGroups = sources.getSourceGroups( + JavaProjectConstants.SOURCES_TYPE_RESOURCES ); + if (sourceGroups != null && sourceGroups.length > 0) { + FileObject fileObject = getDefaultBeansTargetFolder(sourceGroups, false); + if (fileObject != null) { + result.add(fileObject); + } + } + else { + sourceGroups = sources.getSourceGroups( + JavaProjectConstants.SOURCES_TYPE_JAVA); + FileObject fileObject = getDefaultBeansTargetFolder(sourceGroups, false); + if ( fileObject != null ){ + result.add(fileObject); + } + } + if ( result.isEmpty() && create ){ + SourceGroup resourcesSourceGroup = SourceGroupModifier.createSourceGroup( + project, JavaProjectConstants.SOURCES_TYPE_RESOURCES, + JavaProjectConstants.SOURCES_HINT_MAIN); + if ( resourcesSourceGroup != null ){ + sourceGroups = new SourceGroup[]{resourcesSourceGroup}; + } + FileObject fileObject = getDefaultBeansTargetFolder(sourceGroups, true); + result.add(fileObject); + } + return result; + } + + private static FileObject getDefaultBeansTargetFolder( SourceGroup[] sourceGroups, + boolean create ) + { + if ( sourceGroups.length >0 ){ + FileObject metaInf = sourceGroups[0].getRootFolder().getFileObject( META_INF ); + if ( metaInf == null && create ){ + try { + metaInf = FileUtil.createFolder( + sourceGroups[0].getRootFolder(), META_INF); + } + catch( IOException e ){ + Logger.getLogger( CdiUtil.class.getName() ).log( + Level.WARNING, null, e ); + } + } + return metaInf; + } + return null; + } + + private WeakReference myProject; + private Set myMessages; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/EjbCdiUtil.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/EjbCdiUtil.java new file mode 100644 index 000000000000..1c5fe1ba295b --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/EjbCdiUtil.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans; + +import java.util.Collection; +import java.util.Collections; + +import org.netbeans.api.project.Project; +import org.netbeans.modules.j2ee.api.ejbjar.EjbJar; +import org.netbeans.spi.project.ProjectServiceProvider; +import org.netbeans.spi.project.ui.ProjectOpenedHook; +import org.openide.filesystems.FileObject; + + + +/** + * @author ads + * + */ +@ProjectServiceProvider(service=CdiUtil.class, projectType = { + "org-netbeans-modules-j2ee-ejbjarproject", "org-netbeans-modules-maven/ejb"}) +public class EjbCdiUtil extends CdiUtil { + + public EjbCdiUtil( Project project ) { + super(project); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.CdiUtil#getBeansTargetFolder(boolean) + */ + @Override + public Collection getBeansTargetFolder(boolean create) + { + Project project = getProject(); + if ( project == null ){ + return Collections.emptyList(); + } + EjbJar ejbs[] = EjbJar.getEjbJars(project); + if (ejbs.length > 0) { + return Collections.singleton(ejbs[0].getMetaInf()); + } + return super.getBeansTargetFolder(create); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/MetaModelSupport.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/MetaModelSupport.java new file mode 100644 index 000000000000..8f70d513704c --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/MetaModelSupport.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans; + + + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.WeakHashMap; + +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.java.project.JavaProjectConstants; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.api.project.Sources; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.web.api.webmodule.WebProjectConstants; +import org.netbeans.modules.jakarta.web.beans.api.model.ModelUnit; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModelFactory; + +import org.netbeans.spi.java.classpath.ClassPathProvider; +import org.netbeans.spi.java.classpath.support.ClassPathSupport; +import org.openide.filesystems.FileObject; + +/** + * @author ads + * + */ +public class MetaModelSupport { + + public MetaModelSupport( Project project ){ + myProject = project; + } + + public MetadataModel getMetaModel(){ + synchronized (MODELS) { + MetadataModel metadataModel = MODELS.get( myProject ); + if ( metadataModel != null ){ + return metadataModel; + } + ClassPath boot = getClassPath( ClassPath.BOOT); + ClassPath compile = getClassPath( ClassPath.COMPILE ); + ClassPath src = getClassPath( ClassPath.SOURCE); + if ( boot == null || compile == null || src == null ){ + return null; + } + ModelUnit modelUnit = ModelUnit.create( boot, compile , src, myProject); + metadataModel = WebBeansModelFactory.getMetaModel( modelUnit ); + MODELS.put( myProject, metadataModel ); + return metadataModel; + } + } + + public ClassPath getClassPath( String type ) { + ClassPathProvider provider = getProject().getLookup().lookup( + ClassPathProvider.class); + if ( provider == null ){ + return null; + } + Sources sources = getProject().getLookup().lookup(Sources.class); + if ( sources == null ){ + return null; + } + SourceGroup[] sourceGroups = sources.getSourceGroups( + JavaProjectConstants.SOURCES_TYPE_JAVA ); + SourceGroup[] webGroup = sources.getSourceGroups( + WebProjectConstants.TYPE_WEB_INF); + ClassPath[] paths = new ClassPath[ sourceGroups.length+webGroup.length]; + int i=0; + for (SourceGroup sourceGroup : sourceGroups) { + FileObject rootFolder = sourceGroup.getRootFolder(); + paths[ i ] = provider.findClassPath( rootFolder, type); + i++; + } + for (SourceGroup sourceGroup : webGroup) { + FileObject rootFolder = sourceGroup.getRootFolder(); + paths[ i ] = provider.findClassPath( rootFolder, type); + i++; + } + return ClassPathSupport.createProxyClassPath( paths ); + } + + private Project getProject(){ + return myProject; + } + + private Project myProject; + + private static WeakHashMap> + MODELS = new WeakHashMap>(); +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/WebBeanInjectionTargetQueryImplementation.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/WebBeanInjectionTargetQueryImplementation.java new file mode 100644 index 000000000000..761f3b6a66fb --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/WebBeanInjectionTargetQueryImplementation.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans; + +import java.io.IOException; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.TypeElement; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.modules.javaee.injection.spi.InjectionTargetQueryImplementation; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelException; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +import org.openide.util.Parameters; + + +/** + * @author ads + * + */ +@org.openide.util.lookup.ServiceProvider(service=org.netbeans.modules.javaee.injection.spi.InjectionTargetQueryImplementation.class) +public class WebBeanInjectionTargetQueryImplementation implements + InjectionTargetQueryImplementation +{ + + /* (non-Javadoc) + * @see org.netbeans.modules.j2ee.common.queries.spi.InjectionTargetQueryImplementation#isInjectionTarget(org.netbeans.modules.j2ee.common.queries.spi.CompilationController, javax.lang.model.element.TypeElement) + */ + @Override + public boolean isInjectionTarget( CompilationController controller, + TypeElement typeElement ) + { + try { + Parameters.notNull("controller", controller); + Parameters.notNull("typeElement", typeElement); + + Project project = FileOwnerQuery.getOwner( controller.getFileObject() ); + if ( project == null ){ + return false; + } + MetaModelSupport support = new MetaModelSupport(project); + MetadataModel metaModel = support.getMetaModel(); + final ElementHandle handle = ElementHandle.create(typeElement); + return metaModel.runReadAction(new MetadataModelAction() { + + @Override + public Boolean run( WebBeansModel model ) throws Exception { + TypeElement element = handle.resolve(model.getCompilationController()); + if ( element == null ){ + return false; + } + List qualifiers = model.getQualifiers( + element, true); + if ( qualifiers.size() == 0 ){ + /* + * @Named is special case. + * It could be present implicitly : there are + * stereotype declared for the element which + * is annotated by @Named. + */ + if ( model.getName( element ) != null ){ + return true; + } + return false; + } + else { + /* + * There are some qualifiers. + * So this bean is eligible for injection. But it + * doesn't mean it is really managed by J2EE container. + */ + return true; + } + } + }); + } catch (MetadataModelException ex) { + Logger.getLogger( WebBeanInjectionTargetQueryImplementation.class.getName()). + log( Level.WARNING, ex.getMessage(), ex); + } catch (IOException ex) { + Logger.getLogger( WebBeanInjectionTargetQueryImplementation.class.getName()). + log( Level.WARNING, ex.getMessage(), ex); + } + return false; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.j2ee.common.queries.spi.InjectionTargetQueryImplementation#isStaticReferenceRequired(org.netbeans.modules.j2ee.common.queries.spi.CompilationController, javax.lang.model.element.TypeElement) + */ + @Override + public boolean isStaticReferenceRequired( CompilationController controller, + TypeElement typeElement ) + { + return false; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/WebCdiUtil.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/WebCdiUtil.java new file mode 100644 index 000000000000..33607ae0a78a --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/WebCdiUtil.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans; + +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.netbeans.api.project.Project; +import org.netbeans.modules.web.api.webmodule.WebModule; +import org.netbeans.spi.project.ProjectServiceProvider; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; + + +/** + * @author ads + * + */ +@ProjectServiceProvider(service={CdiUtil.class}, projectType = { + "org-netbeans-modules-web-project", "org-netbeans-modules-maven/war"}) +public class WebCdiUtil extends CdiUtil { + + public WebCdiUtil( Project project ) { + super(project); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.CdiUtil#getBeansTargetFolder(boolean) + */ + @Override + public Collection getBeansTargetFolder( boolean create ) { + Project project = getProject(); + if ( project == null ){ + return Collections.emptyList(); + } + WebModule wm = WebModule.getWebModule(project.getProjectDirectory()); + if (wm != null && wm.getDocumentBase() != null) { + FileObject webInf = wm.getWebInf(); + if (webInf == null && create ) { + try { + webInf = FileUtil.createFolder(wm.getDocumentBase(), WEB_INF); + } catch (IOException ex) { + Logger.getLogger( WebCdiUtil.class.getName() ).log( + Level.WARNING, null, ex ); + } + } + return Collections.singleton(webInf); + } + return super.getBeansTargetFolder(create); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/actions/Bundle.properties b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/actions/Bundle.properties new file mode 100644 index 000000000000..034e41231a39 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/actions/Bundle.properties @@ -0,0 +1,31 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +LBL_GenerateInterceptor=Generate Interceptor... +LBL_InterceptorName=Choose &Interceptor Name: +ACSN_InterceptorName=Interceptor name chooser +ACSD_InterceptorName=Enter interceptor name + +TITLE_Interceptor=Create Interceptor For "{0}" Interceptor Binding +LBL_InvalidInterceptorName="{0}" is not valid Java type name. +LBL_FileExists=File "{0}" already exists. + +LBL_OK=&OK +LBL_Cancel=&Cancel + +USG_CDI_GENERATE_INTERCEPTOR=Generated interceptor via editor "Insert Code..." \ +context popup menu action for project "{0}". diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/actions/InterceptorFactory.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/actions/InterceptorFactory.java new file mode 100644 index 000000000000..101acea9d17e --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/actions/InterceptorFactory.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.actions; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; +import javax.swing.text.JTextComponent; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.JavaSource; +import org.netbeans.spi.editor.codegen.CodeGenerator; +import org.netbeans.spi.editor.codegen.CodeGenerator.Factory; +import org.openide.util.Lookup; + +import com.sun.source.util.TreePath; + + +/** + * @author ads + * + */ +public class InterceptorFactory implements Factory { + + static final String INTERCEPTOR_BINDING = "InterceptorBinding"; // NOI18N + + private static final String INTERCEPTOR_BINDING_FQN = + "jakarta.interceptor." +INTERCEPTOR_BINDING; // NOI18N + + /* (non-Javadoc) + * @see org.netbeans.spi.editor.codegen.CodeGenerator.Factory#create(org.openide.util.Lookup) + */ + @Override + public List create( Lookup lookup ) { + CompilationController controller = lookup.lookup(CompilationController.class); + JTextComponent component = lookup.lookup(JTextComponent.class); + List result = new ArrayList(1); + if (component != null && controller != null) { + try { + controller.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); + + TypeElement interceptorBinding = controller.getElements(). + getTypeElement( INTERCEPTOR_BINDING_FQN ); + if ( interceptorBinding == null ){ + return result; + } + int dot = component.getCaret().getDot(); + TreePath tp = controller.getTreeUtilities().pathFor(dot); + if ( tp == null ){ + return result; + } + Element contextElement = controller.getTrees().getElement(tp ); + if ( contextElement == null || + contextElement.getKind() != ElementKind.ANNOTATION_TYPE ) + { + return result; + } + + List annotations = controller. + getElements().getAllAnnotationMirrors( contextElement ); + boolean isInterceptorBinding = false; + for (AnnotationMirror annotation : annotations) { + Element annotationElement = controller.getTypes().asElement( + annotation.getAnnotationType()); + if ( interceptorBinding.equals( annotationElement) ){ + isInterceptorBinding = true; + break; + } + } + if ( isInterceptorBinding ){ + result.add( new InterceptorGenerator( + contextElement.getSimpleName().toString(), + controller.getFileObject()) ); + } + } catch (IOException ex) { + Logger.getLogger( InterceptorFactory.class.getName()).log( + Level.INFO, null, ex ); + } + } + return result; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/actions/InterceptorGenerator.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/actions/InterceptorGenerator.java new file mode 100644 index 000000000000..7539108adc32 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/actions/InterceptorGenerator.java @@ -0,0 +1,264 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.actions; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.swing.JButton; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.ui.ElementOpen; +import org.netbeans.api.java.source.JavaSource; +import org.netbeans.api.java.source.ModificationResult; +import org.netbeans.api.java.source.CancellableTask; +import org.netbeans.api.java.source.Task; +import org.netbeans.api.java.source.TreeMaker; +import org.netbeans.api.java.source.TreeUtilities; +import org.netbeans.api.java.source.WorkingCopy; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.modules.jakarta.web.beans.CdiUtil; +import org.netbeans.spi.editor.codegen.CodeGenerator; +import org.openide.DialogDescriptor; +import org.openide.DialogDisplayer; +import org.openide.awt.Mnemonics; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.loaders.DataFolder; +import org.openide.loaders.DataObject; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; + +import com.sun.source.tree.AnnotationTree; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.ModifiersTree; +import com.sun.source.tree.Tree; + + +/** + * @author ads + * + */ +class InterceptorGenerator implements CodeGenerator { + + private static final Logger LOG = Logger.getLogger( + InterceptorGenerator.class.getName() ); + + private static final String INTERCEPTOR = "javax.interceptor.Interceptor"; // NOI18N + + InterceptorGenerator( String bindingName, FileObject bindingFileObject ) { + myBindingName = bindingName; + myBindingFileObject = bindingFileObject; + } + + /* (non-Javadoc) + * @see org.netbeans.spi.editor.codegen.CodeGenerator#getDisplayName() + */ + @Override + public String getDisplayName() { + return NbBundle.getMessage( InterceptorGenerator.class, + "LBL_GenerateInterceptor"); // NOI18N + } + + /* (non-Javadoc) + * @see org.netbeans.spi.editor.codegen.CodeGenerator#invoke() + */ + @Override + public void invoke() { + JButton ok = new JButton(); + Mnemonics.setLocalizedText(ok, NbBundle.getMessage(InterceptorGenerator.class, + "LBL_OK") ); // NOI18N + JButton cancel = new JButton(); + Mnemonics.setLocalizedText(cancel, NbBundle.getMessage(InterceptorGenerator.class, + "LBL_Cancel")); // NOI18N + + InterceptorPanel panel = new InterceptorPanel( ok , myBindingName, + myBindingFileObject); + + DialogDescriptor descriptor = new DialogDescriptor( panel, + NbBundle.getMessage(InterceptorGenerator.class, "TITLE_Interceptor",// NOI18N + myBindingName ), + true, new Object[]{ ok, cancel }, + null, DialogDescriptor.DEFAULT_ALIGN, + new HelpCtx(InterceptorGenerator.class), + null); + descriptor.setClosingOptions( new Object[] { ok , cancel }); + Object closedOption = DialogDisplayer.getDefault().notify( descriptor ); + FileObject targetFolder = myBindingFileObject.getParent(); + if ( closedOption == ok && targetFolder != null ){ + createInterceptor(panel, targetFolder); + } + } + + private void createInterceptor( InterceptorPanel panel, + FileObject targetFolder ) + { + FileObject templateFileObject = FileUtil.getConfigFile( + "Templates/Classes/Class.java"); // NOI18N + try { + DataObject templateDataObject = DataObject + .find(templateFileObject); + DataFolder dataFolder = DataFolder.findFolder(targetFolder); + DataObject createdDataObject = templateDataObject.createFromTemplate( + dataFolder,panel.getInterceptorName(), + Collections. emptyMap()); + modifyClass( createdDataObject.getPrimaryFile() , + getType(myBindingFileObject, ElementKind.ANNOTATION_TYPE)); + + Project project = FileOwnerQuery.getOwner(myBindingFileObject); + if ( project != null ){ + CdiUtil logger = project.getLookup().lookup(CdiUtil.class); + if ( logger != null ){ + logger.log("USG_CDI_GENERATE_INTERCEPTOR", // NOI18N + InterceptorGenerator.class, + new Object[]{project.getClass().getName()}); + } + } + } + catch (IOException e) { + LOG.log(Level.WARNING , null , e ); + } + } + + private ElementHandle getType( FileObject fileObject , + final ElementKind kind ) throws IOException + { + JavaSource javaSource = JavaSource.forFileObject(fileObject); + final List> result = + new ArrayList>(1); + javaSource.runUserActionTask( new Task() { + + @Override + public void run( CompilationController controller ) throws Exception { + controller.toPhase(JavaSource.Phase.RESOLVED); + + String typeName = controller.getFileObject().getName(); + List topLevelElements = + controller.getTopLevelElements(); + for (TypeElement typeElement : topLevelElements) { + if ( kind == typeElement.getKind() && typeName.contentEquals( + typeElement.getSimpleName())) + { + result.add(ElementHandle.create( typeElement)); + return; + } + } + } + },true); + return result.get(0); + } + + private void modifyClass( FileObject fileObject , + final ElementHandle handle ) + { + JavaSource javaSource = JavaSource.forFileObject(fileObject); + try { + ModificationResult result = javaSource.runModificationTask( + new CancellableTask() { + + @Override + public void run(WorkingCopy copy) throws IOException { + copy.toPhase(JavaSource.Phase.RESOLVED); + + TreeMaker maker = copy.getTreeMaker(); + ClassTree tree = getTopLevelClassTree(copy); + if ( tree ==null ){ + return; + } + Element element = copy.getTrees().getElement( + copy.getTrees().getPath(copy.getCompilationUnit(), tree) ); + + ModifiersTree modifiers = tree.getModifiers(); + + modifiers = addAnnotation(INTERCEPTOR, maker, modifiers); + TypeElement annotation = handle.resolve( copy ); + if ( annotation != null ){ + modifiers = addAnnotation(annotation.getQualifiedName().toString(), + maker, modifiers); + } + + copy.rewrite(tree.getModifiers(), modifiers); + + ElementOpen.open(copy.getClasspathInfo(), element); + } + + private ModifiersTree addAnnotation( String annotationFqn , + TreeMaker maker,ModifiersTree modifiers ) + { + AnnotationTree newAnnotation = maker.Annotation( + maker.QualIdent(annotationFqn) , + Collections.emptyList()); + + if (modifiers != null) { + modifiers = maker.addModifiersAnnotation(modifiers, + newAnnotation); + } + return modifiers; + } + + @Override + public void cancel() { + } + }); + result.commit(); + } + catch (IOException e) { + LOG.log(Level.WARNING , null , e ); + } + + } + + public static ClassTree getTopLevelClassTree(CompilationController controller) { + String className = controller.getFileObject().getName(); + + CompilationUnitTree cu = controller.getCompilationUnit(); + if (cu != null) { + List decls = cu.getTypeDecls(); + for (Tree decl : decls) { + if (!TreeUtilities.CLASS_TREE_KINDS.contains(decl.getKind())) { + continue; + } + + ClassTree classTree = (ClassTree) decl; + + if (classTree.getSimpleName().contentEquals(className) && + classTree.getModifiers().getFlags().contains(Modifier.PUBLIC)) { + return classTree; + } + } + } + return null; + } + + + private String myBindingName; + private FileObject myBindingFileObject; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/actions/InterceptorPanel.form b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/actions/InterceptorPanel.form new file mode 100644 index 000000000000..16680ddd9bcd --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/actions/InterceptorPanel.form @@ -0,0 +1,98 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/actions/InterceptorPanel.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/actions/InterceptorPanel.java new file mode 100644 index 000000000000..9c305c302dd9 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/actions/InterceptorPanel.java @@ -0,0 +1,218 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * InterceptorPanel.java + * + * Created on 06.04.2011, 11:10:22 + */ +package org.netbeans.modules.jakarta.web.beans.actions; + +import java.net.MalformedURLException; +import java.net.URL; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; + +import org.openide.filesystems.FileObject; +import org.openide.util.NbBundle; +import org.openide.util.Utilities; + +/** + * + * @author den + */ +public class InterceptorPanel extends javax.swing.JPanel { + + private static final long serialVersionUID = 984990919698645497L; + + private static final String JAVA = "java"; // NOI18N + + + public InterceptorPanel( JButton approveButton, String bindingName, + FileObject bindingFileObject ) + { + initComponents(); + myBindingName = bindingName; + myBindingFileObject = bindingFileObject; + + myInterceptorName.getDocument().addDocumentListener( + createValidationListener( approveButton ) ); + myInterceptorName.setText( getProposedName() ); + URL errorUrl; + try { + errorUrl = new URL("nbresloc:/org/netbeans/modules/dialogs/error.gif"); + myStatusLbl.setIcon( new ImageIcon( errorUrl )); + } + catch (MalformedURLException e) { + assert false; + } + + myStatusLbl.setVisible( false ); + } + + String getInterceptorName(){ + return myInterceptorName.getText(); + } + + private DocumentListener createValidationListener(final JButton button ) { + DocumentListener listener = new DocumentListener() { + + @Override + public void removeUpdate( DocumentEvent e ) { + checkName(e); + } + + @Override + public void insertUpdate( DocumentEvent e ) { + checkName(e); + } + + @Override + public void changedUpdate( DocumentEvent e ) { + checkName(e); + } + + private void checkName(DocumentEvent e){ + try { + String text = e.getDocument().getText(0, + e.getDocument().getLength()); + if ( text == null || text.trim().length() == 0 || + !Utilities.isJavaIdentifier( text )) + { + myStatusLbl.setText(NbBundle.getMessage( + InterceptorGenerator.class, + "LBL_InvalidInterceptorName", text )); + myStatusLbl.setVisible( true ); + button.setEnabled( false ); + return; + } + FileObject packageFolder = myBindingFileObject.getParent(); + if ( packageFolder == null ){ + return; + } + FileObject file = packageFolder.getFileObject( text,JAVA); + if ( file != null ){ + myStatusLbl.setText(NbBundle.getMessage( + InterceptorGenerator.class, + "LBL_FileExists", file.getNameExt() )); + myStatusLbl.setVisible( true ); + button.setEnabled( false ); + return; + } + + myStatusLbl.setText(""); + myStatusLbl.setVisible( false ); + button.setEnabled( true ); + } + catch (BadLocationException ex ) { + /* + * should be never appear because text access is done inside + * event handling + */ + assert false; + } + } + }; + return listener; + } + + private String getProposedName() { + StringBuilder result = new StringBuilder(); + if ( myBindingName.endsWith(InterceptorFactory.INTERCEPTOR_BINDING)){ + result.append( myBindingName.substring(0, myBindingName.length() - + InterceptorFactory.INTERCEPTOR_BINDING.length() )); + } + else { + result.append( myBindingName ); + } + result.append("Interceptor"); // NOI18N + + FileObject packageFolder = myBindingFileObject.getParent(); + if ( packageFolder == null ){ + return result.toString(); + } + int index = 1; + String next = result.toString(); + while( packageFolder.getFileObject( next, JAVA) != null ){ + next = result.toString()+index; + index++; + } + return result.toString(); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + myInterceptorNameLbl = new javax.swing.JLabel(); + myInterceptorName = new javax.swing.JTextField(); + myStatusLbl = new javax.swing.JLabel(); + + org.openide.awt.Mnemonics.setLocalizedText(myInterceptorNameLbl, org.openide.util.NbBundle.getMessage(InterceptorPanel.class, "LBL_InterceptorName")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(myInterceptorNameLbl) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(myInterceptorName, javax.swing.GroupLayout.DEFAULT_SIZE, 244, Short.MAX_VALUE)) + .addComponent(myStatusLbl)) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(myInterceptorNameLbl) + .addComponent(myInterceptorName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 20, Short.MAX_VALUE) + .addComponent(myStatusLbl) + .addContainerGap()) + ); + + myInterceptorNameLbl.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(InterceptorPanel.class, "ACSN_InterceptorName")); // NOI18N + myInterceptorNameLbl.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(InterceptorPanel.class, "ACSD_InterceptorName")); // NOI18N + myInterceptorName.getAccessibleContext().setAccessibleName(myInterceptorNameLbl.getAccessibleContext().getAccessibleName()); + myInterceptorName.getAccessibleContext().setAccessibleDescription(getAccessibleContext().getAccessibleDescription()); + }// //GEN-END:initComponents + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JTextField myInterceptorName; + private javax.swing.JLabel myInterceptorNameLbl; + private javax.swing.JLabel myStatusLbl; + // End of variables declaration//GEN-END:variables + + private String myBindingName; + private FileObject myBindingFileObject; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/AbstractAnalysisTask.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/AbstractAnalysisTask.java new file mode 100644 index 000000000000..f5c18d134a10 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/AbstractAnalysisTask.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.spi.editor.hints.ErrorDescription; + + +/** + * @author ads + * + */ +abstract class AbstractAnalysisTask { + + AbstractAnalysisTask( ){ + cancel = new AtomicBoolean( false ); + } + + protected boolean isCancelled() { + return cancel.get(); + } + + protected AtomicBoolean getCancel(){ + return cancel; + } + + protected CdiAnalysisResult getResult(){ + return myResult; + } + + protected void setResult( CdiAnalysisResult result ){ + myResult = result; + } + + abstract void run( CompilationInfo compInfo ); + + abstract List getProblems(); + + void stop(){ + cancel.set( true ); + } + + private AtomicBoolean cancel; + private CdiAnalysisResult myResult; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/BeansXmlFix.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/BeansXmlFix.java new file mode 100644 index 000000000000..eea1f406e205 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/BeansXmlFix.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import java.util.Collection; +import java.util.Iterator; + +import org.netbeans.api.j2ee.core.Profile; +import org.netbeans.api.project.Project; +import org.netbeans.modules.j2ee.common.dd.DDHelper; +import org.netbeans.modules.jakarta.web.beans.CdiUtil; +import org.netbeans.spi.editor.hints.ChangeInfo; +import org.netbeans.spi.editor.hints.Fix; +import org.openide.filesystems.FileObject; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +class BeansXmlFix implements Fix { + + BeansXmlFix( Project project , FileObject fileObject , + CdiEditorAwareJavaSourceTaskFactory factory ) + { + myProject = project; + myFileObject = fileObject; + myFactory = factory; + } + + /* (non-Javadoc) + * @see org.netbeans.spi.editor.hints.Fix#getText() + */ + @Override + public String getText() { + return NbBundle.getMessage( BeansXmlFix.class, "MSG_HintCreateBeansXml"); // NOI18N + } + + /* (non-Javadoc) + * @see org.netbeans.spi.editor.hints.Fix#implement() + */ + @Override + public ChangeInfo implement() throws Exception { + CdiUtil util = myProject.getLookup().lookup( CdiUtil.class); + Collection infs; + if ( util == null ){ + infs= CdiUtil.getBeansTargetFolder(myProject, true); + } + else { + infs = util.getBeansTargetFolder(true); + } + for (FileObject inf : infs) { + if (inf != null) { + FileObject beansXml = inf + .getFileObject(CdiUtil.BEANS_XML); + if (beansXml != null) { + return null; + } + DDHelper.createBeansXml(Profile.JAVA_EE_6_FULL, inf, + CdiUtil.BEANS); + CdiUtil logger = myProject.getLookup().lookup(CdiUtil.class); + if ( logger!= null ){ + logger.log("USG_CDI_BEANS_FIX", BeansXmlFix.class, + new Object[]{myProject.getClass().getName()}, true ); + } + if (myFactory != null) { + myFactory.restart(myFileObject); + } + return null; + } + } + return null; + } + + private Project myProject; + private CdiEditorAwareJavaSourceTaskFactory myFactory; + private FileObject myFileObject; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/Bundle.properties b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/Bundle.properties new file mode 100644 index 000000000000..a7bbcd24d870 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/Bundle.properties @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +ERR_RequireWebBeans=CDI artifact is found but there is no beans.xml file. +MSG_HintCreateBeansXml=Create beans.xml file + +USG_CDI_BEANS_FIX=beans.xml file is created via fix hint for project "{0}". \ No newline at end of file diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/CancellableAnalysysTask.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/CancellableAnalysysTask.java new file mode 100644 index 000000000000..6b1e5f15bb5a --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/CancellableAnalysysTask.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import java.util.concurrent.atomic.AtomicReference; + +import org.netbeans.api.java.source.CancellableTask; +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.modules.jakarta.web.beans.navigation.actions.WebBeansActionHelper; +import org.netbeans.spi.editor.hints.HintsController; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +abstract class CancellableAnalysysTask implements CancellableTask{ + + CancellableAnalysysTask(FileObject javaFile, + CdiEditorAwareJavaSourceTaskFactory factory ) + { + myFileObject = javaFile; + myTask = new AtomicReference(); + myFactory = factory; + } + + /* (non-Javadoc) + * @see org.netbeans.api.java.source.Task#run(java.lang.Object) + */ + @Override + public void run( CompilationInfo compInfo ) throws Exception { + if ( !WebBeansActionHelper.isEnabled() ){ + return; + } + AbstractAnalysisTask task = createTask(); + myTask.set( task ); + task.run( compInfo ); + myTask.compareAndSet( task, null); + HintsController.setErrors(myFileObject, getLayerName(), task.getProblems()); + } + + /* (non-Javadoc) + * @see org.netbeans.api.java.source.CancellableTask#cancel() + */ + @Override + public void cancel() { + AbstractAnalysisTask task = myTask.getAndSet(null); + if ( task != null ){ + task.stop(); + } + } + + protected abstract String getLayerName(); + + protected abstract AbstractAnalysisTask createTask(); + + protected FileObject getFileObject(){ + return myFileObject; + } + + protected CdiEditorAwareJavaSourceTaskFactory getFactory(){ + return myFactory; + } + + private FileObject myFileObject; + private AtomicReference myTask; + private CdiEditorAwareJavaSourceTaskFactory myFactory; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiAnalysisResult.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiAnalysisResult.java new file mode 100644 index 000000000000..95d2865c1ac0 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiAnalysisResult.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import javax.lang.model.element.Element; + +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.modules.jakarta.web.beans.CdiUtil; +import org.netbeans.modules.jakarta.web.beans.hints.CDIAnnotation; +import org.netbeans.spi.editor.hints.ErrorDescription; +import org.netbeans.spi.editor.hints.Fix; +import org.netbeans.spi.editor.hints.Severity; +import org.openide.filesystems.FileObject; +import org.openide.util.NbBundle; + + + +/** + * @author ads + * + */ +public class CdiAnalysisResult { + + public CdiAnalysisResult( CompilationInfo info, + CdiEditorAwareJavaSourceTaskFactory factory ) + { + myInfo = info; + myProblems = new LinkedList(); + myCollectedAnnotations = new LinkedList(); + } + + public void addError( Element subject, String message ) { + addNotification( Severity.ERROR, subject, message); + } + + public void addError( Element subject, String message , Fix fix ) { + addNotification( Severity.ERROR, subject, message, fix ); + } + + public void addNotification( Severity severity, + Element element, String message ) + { + addNotification(severity, element, message , null ); + } + + public void addNotification( Severity severity, + Element element, String message , Fix fix ) + { + ErrorDescription description = CdiEditorAnalysisFactory. + createNotification( severity, element, myInfo , message, fix ); + if ( description == null ){ + return; + } + getProblems().add( description ); + } + + public CompilationInfo getInfo() { + return myInfo; + } + + public List getProblems(){ + return myProblems; + } + + public void requireCdiEnabled( Element element ){ + if ( isCdiRequired ){ + return; + } + isCdiRequired = true; + FileObject fileObject = getInfo().getFileObject(); + if ( fileObject ==null ){ + return; + } + Project project = FileOwnerQuery.getOwner( fileObject ); + if ( project == null ){ + return; + } + CdiUtil lookup = project.getLookup().lookup( CdiUtil.class ); + boolean needFix = false; + if ( lookup == null ){ + //in general main use is is when lookup!=null, if lookup == null nly some general hevavior is supported + needFix = !CdiUtil.isCdiEnabled(project); + } + else { + needFix = !lookup.isCdiEnabled(); + } + if ( needFix) { + Fix fix = new BeansXmlFix( project , fileObject , myFactory ); + addError(element, NbBundle.getMessage(CdiAnalysisResult.class, + "ERR_RequireWebBeans"), fix ); // NOI18N + } + } + + public boolean requireBeansXml(){ + return isCdiRequired; + } + + public void addAnnotation( CDIAnnotation annotation ) { + myCollectedAnnotations.add(annotation); + } + + public List getAnnotations(){ + return Collections.unmodifiableList(myCollectedAnnotations); + } + + private CompilationInfo myInfo ; + private List myProblems; + private boolean isCdiRequired; + private List myCollectedAnnotations; + private CdiEditorAnalysisFactory myFactory; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiAnalysisTask.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiAnalysisTask.java new file mode 100644 index 000000000000..452f9df05d7d --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiAnalysisTask.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.ElementFilter; + +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationElementAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ClassElementAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.CtorAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.FieldElementAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.MethodElementAnalyzer; +import org.netbeans.modules.jakarta.web.beans.hints.EditorAnnotationsHelper; +import org.netbeans.spi.editor.hints.ErrorDescription; + + +/** + * @author ads + * + */ +public class CdiAnalysisTask extends AbstractAnalysisTask { + + public CdiAnalysisTask( CdiEditorAwareJavaSourceTaskFactory factory ){ + myFactory =factory; + } + + + protected CdiAnalysisResult createResult( CompilationInfo info ){ + return new CdiAnalysisResult(info, myFactory ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.AbstractAnalysisTask#getProblems() + */ + @Override + List getProblems() { + return getResult().getProblems(); + } + + @Override + protected void run( CompilationInfo compInfo ) { + setResult( createResult( compInfo ) ); + List types = compInfo.getTopLevelElements(); + for (TypeElement typeElement : types) { + if ( isCancelled() ){ + break; + } + analyzeType(typeElement, null ); + } + EditorAnnotationsHelper helper = EditorAnnotationsHelper.getInstance(getResult()); + if ( helper == null ){ + return; + } + helper.publish( getResult() ); + } + + private void analyzeType(TypeElement typeElement , TypeElement parent ) + { + ElementKind kind = typeElement.getKind(); + ElementAnalyzer analyzer = ANALIZERS.get( kind ); + if ( analyzer != null ){ + analyzer.analyze(typeElement, parent, getCancel(), getResult() ); + } + if ( isCancelled() ){ + return; + } + List enclosedElements = typeElement.getEnclosedElements(); + List types = ElementFilter.typesIn(enclosedElements); + for (TypeElement innerType : types) { + analyzeType(innerType, typeElement ); + } + Set enclosedSet = new HashSet( enclosedElements ); + enclosedSet.removeAll( types ); + for(Element element : enclosedSet ){ + analyze(typeElement, element); + } + } + + private void analyze( TypeElement typeElement, Element element ) + { + ElementAnalyzer analyzer; + if ( isCancelled() ){ + return; + } + analyzer = ANALIZERS.get( element.getKind() ); + if ( analyzer == null ){ + return; + } + analyzer.analyze(element, typeElement, getCancel(), getResult() ); + } + + private CdiEditorAwareJavaSourceTaskFactory myFactory; + private static final Map ANALIZERS = + new HashMap(); + + static { + ANALIZERS.put(ElementKind.CLASS, new ClassElementAnalyzer()); + ANALIZERS.put(ElementKind.FIELD, new FieldElementAnalyzer()); + ANALIZERS.put(ElementKind.METHOD, new MethodElementAnalyzer()); + ANALIZERS.put(ElementKind.CONSTRUCTOR, new CtorAnalyzer()); + ANALIZERS.put(ElementKind.ANNOTATION_TYPE, new AnnotationElementAnalyzer()); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiEditorAnalysisFactory.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiEditorAnalysisFactory.java new file mode 100644 index 000000000000..dac280b9cc25 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiEditorAnalysisFactory.java @@ -0,0 +1,232 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; + +import org.netbeans.api.java.lexer.JavaTokenId; +import org.netbeans.api.java.source.CancellableTask; +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.JavaSource.Phase; +import org.netbeans.api.java.source.JavaSource.Priority; +import org.netbeans.api.java.source.JavaSourceTaskFactory; +import org.netbeans.api.java.source.TreeUtilities; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.spi.editor.hints.ErrorDescription; +import org.netbeans.spi.editor.hints.ErrorDescriptionFactory; +import org.netbeans.spi.editor.hints.Fix; +import org.netbeans.spi.editor.hints.Severity; +import org.openide.filesystems.FileObject; +import org.openide.util.lookup.ServiceProvider; + +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.MethodTree; +import com.sun.source.tree.Tree; +import com.sun.source.tree.VariableTree; +import com.sun.source.util.SourcePositions; + + +/** + * @author ads + * + */ +@ServiceProvider(service=JavaSourceTaskFactory.class) +public class CdiEditorAnalysisFactory extends CdiEditorAwareJavaSourceTaskFactory { + + public CdiEditorAnalysisFactory( ){ + super(Priority.BELOW_NORMAL); + } + + /* (non-Javadoc) + * @see org.netbeans.api.java.source.JavaSourceTaskFactory#createTask(org.openide.filesystems.FileObject) + */ + @Override + protected CancellableTask createTask( FileObject fileObject ) { + return new CdiEditorAnalysisTask( fileObject , this ); + } + + public static ErrorDescription createError( Element subject , + CompilationInfo info ,String description) + { + return createNotification(Severity.ERROR, subject, info, description); + } + + public static ErrorDescription createNotification( Severity severity, + Element subject , CompilationInfo info ,String description) + { + return createNotification(severity, subject, info, description, null); + } + + public static ErrorDescription createNotification( Severity severity, + Element subject , CompilationInfo info ,String description, Fix fix ) + { + Tree elementTree = info.getTrees().getTree(subject); + return createNotification(severity, elementTree, info, description, fix ); + } + + public static ErrorDescription createNotification( Severity severity, + Element subject , WebBeansModel model, CompilationInfo info , + String description) + { + return createNotification(severity, subject, model , info, description, + null); + } + + public static ErrorDescription createNotification( Severity severity, + Element subject , WebBeansModel model, CompilationInfo info , + String description, Fix fix ) + { + ElementHandle handle = ElementHandle.create( subject ); + Element element = handle.resolve(info); + if ( element == null){ + return null; + } + Tree elementTree = info.getTrees().getTree(element); + return createNotification(severity, elementTree, info, description, fix ); + } + + public static ErrorDescription createNotification( Severity severity, + VariableElement element, ExecutableElement parent , + WebBeansModel model, CompilationInfo info ,String description, Fix fix) + { + VariableElement var = resolveParameter(element, parent, info); + if ( var == null ){ + return null; + } + Tree elementTree = info.getTrees().getTree(var); + return createNotification(severity, elementTree, info, description, fix ); + } + + public static ErrorDescription createNotification( Severity severity, + VariableElement element, ExecutableElement parent , + WebBeansModel model, CompilationInfo info ,String description) + { + return createNotification( severity, element, parent, model , info , + description, null ); + } + + public static VariableElement resolveParameter( VariableElement element, + ExecutableElement parent,CompilationInfo info ) + { + List parameters = parent.getParameters(); + int i=0; + for (VariableElement param : parameters) { + if ( param.equals( element )){ + break; + } + i++; + } + if ( i == parameters.size() ){ + return null; + } + ElementHandle handle = ElementHandle.create( parent ); + ExecutableElement method = handle.resolve(info); + if ( method == null){ + return null; + } + parameters = method.getParameters(); + int j=0; + VariableElement var = null; + for (VariableElement param : parameters) { + if ( i==j){ + var = param; + } + j++; + } + return var; + } + + private static ErrorDescription createNotification( Severity severity, + Tree tree, CompilationInfo info, String description, Fix fix ) + { + + List fixes; + if ( fix != null ){ + fixes = Collections.singletonList( fix ); + } + else { + fixes = Collections.emptyList(); + } + if (tree != null){ + List position = getElementPosition(info, tree); + if(position.get(1) > position.get(0)) { + return ErrorDescriptionFactory.createErrorDescription( + severity, description, fixes, + info.getFileObject(), position.get(0), position.get(1)); + } + } + return null; + } + + public static List getElementPosition(CompilationInfo info, Tree tree){ + SourcePositions srcPos = info.getTrees().getSourcePositions(); + + int startOffset = (int) srcPos.getStartPosition(info.getCompilationUnit(), tree); + int endOffset = (int) srcPos.getEndPosition(info.getCompilationUnit(), tree); + + Tree startTree = null; + + if (TreeUtilities.CLASS_TREE_KINDS.contains(tree.getKind())){ + startTree = ((ClassTree)tree).getModifiers(); + + } else if (tree.getKind() == Tree.Kind.METHOD){ + startTree = ((MethodTree)tree).getReturnType(); + } else if (tree.getKind() == Tree.Kind.VARIABLE){ + startTree = ((VariableTree)tree).getType(); + } + + if (startTree != null){ + int searchStart = (int) srcPos.getEndPosition(info.getCompilationUnit(), + startTree); + + TokenSequence tokenSequence = info.getTreeUtilities().tokensFor(tree); + + if (tokenSequence != null){ + boolean eob = false; + tokenSequence.move(searchStart); + + do{ + eob = !tokenSequence.moveNext(); + } + while (!eob && tokenSequence.token().id() != JavaTokenId.IDENTIFIER); + + if (!eob){ + Token identifier = tokenSequence.token(); + startOffset = identifier.offset(info.getTokenHierarchy()); + endOffset = startOffset + identifier.length(); + } + } + } + + List result = new ArrayList(2); + result.add(startOffset); + result.add(endOffset ); + return result; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiEditorAnalysisTask.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiEditorAnalysisTask.java new file mode 100644 index 000000000000..6a97c968a7d4 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiEditorAnalysisTask.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +class CdiEditorAnalysisTask extends CancellableAnalysysTask { + + CdiEditorAnalysisTask(FileObject javaFile, + CdiEditorAwareJavaSourceTaskFactory factory ) + { + super( javaFile , factory ); + } + + @Override + protected String getLayerName() { + return "CDI Analyser"; //NOI18N + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.CancellableAnalysysTask#createTask() + */ + @Override + protected AbstractAnalysisTask createTask() { + return new CdiAnalysisTask( getFactory() ); + }; + + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiEditorAwareJavaSourceTaskFactory.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiEditorAwareJavaSourceTaskFactory.java new file mode 100644 index 000000000000..61ba37f7e71f --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiEditorAwareJavaSourceTaskFactory.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import org.netbeans.api.java.source.JavaSource.Phase; +import org.netbeans.api.java.source.JavaSource.Priority; +import org.netbeans.api.java.source.support.EditorAwareJavaSourceTaskFactory; +import org.netbeans.modules.parsing.spi.TaskIndexingMode; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +public abstract class CdiEditorAwareJavaSourceTaskFactory extends + EditorAwareJavaSourceTaskFactory +{ + + protected CdiEditorAwareJavaSourceTaskFactory( Priority priority ) { + super(Phase.RESOLVED, priority, /*TaskIndexingMode.ALLOWED_DURING_SCAN ,*/ + "text/x-java"); // NOI18N + } + + void restart( FileObject fileObject ){ + reschedule( fileObject ); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/WebBeansAnalysisTask.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/WebBeansAnalysisTask.java new file mode 100644 index 000000000000..989d74f569a9 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/WebBeansAnalysisTask.java @@ -0,0 +1,206 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.ElementFilter; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelException; +import org.netbeans.modules.jakarta.web.beans.MetaModelSupport; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationModelAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ClassModelAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.FieldModelAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.MethodModelAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.hints.EditorAnnotationsHelper; +import org.netbeans.spi.editor.hints.ErrorDescription; + + +/** + * @author ads + * + */ +public class WebBeansAnalysisTask extends AbstractAnalysisTask { + + private static final Logger LOG = Logger.getLogger( + WebBeansAnalysisTask.class.getName()); + + public WebBeansAnalysisTask( CdiEditorAwareJavaSourceTaskFactory factory ){ + myFactory = factory; + } + + protected Result createResult( CompilationInfo compInfo ) + { + return new Result( compInfo , myFactory ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.AbstractAnalysisTask#getResult() + */ + @Override + protected Result getResult() { + return (Result)super.getResult(); + } + + protected MetadataModel getModel(CompilationInfo compInfo){ + Project project = FileOwnerQuery.getOwner( compInfo.getFileObject() ); + if ( project == null ){ + return null; + } + MetaModelSupport support = new MetaModelSupport(project); + return support.getMetaModel(); + } + + @Override + List getProblems(){ + return getResult().getProblems(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.AbstractAnalysisTask#run(org.netbeans.api.java.source.CompilationInfo) + */ + @Override + protected void run( final CompilationInfo compInfo ) { + setResult( createResult( compInfo ) ); + List types = compInfo.getTopLevelElements(); + final List> handles = + new ArrayList>(1); + for (TypeElement typeElement : types) { + if ( isCancelled() ){ + break; + } + handles.add(ElementHandle.create(typeElement)); + } + MetadataModel metaModel = getModel(compInfo); + if ( metaModel == null ){ + return; + } + try { + metaModel.runReadAction( + new MetadataModelAction() + { + @Override + public Void run( WebBeansModel model ) throws Exception { + CompilationController controller = model.getCompilationController(); + for (ElementHandle handle : handles) { + if(isCancelled()) { + break; + } + TypeElement type = handle.resolve( controller ); + if ( type == null ){ + continue; + } + analyzeType( type , null , model , compInfo ); + } + return null; + } + }); + } + catch (MetadataModelException e) { + LOG.log( Level.INFO , null , e); + } + catch (IOException e) { + LOG.log( Level.INFO , null , e); + } + finally { + EditorAnnotationsHelper helper = EditorAnnotationsHelper.getInstance(getResult()); + if ( helper == null ){ + return; + } + helper.publish( getResult() ); + } + } + + private void analyzeType(TypeElement typeElement , TypeElement parent , + WebBeansModel model , CompilationInfo info ) + { + ElementKind kind = typeElement.getKind(); + ModelAnalyzer analyzer = ANALIZERS.get( kind ); + if ( analyzer != null ){ + analyzer.analyze(typeElement, parent, model, getCancel(), getResult()); + } + if ( isCancelled() ){ + return; + } + List enclosedElements = typeElement.getEnclosedElements(); + List types = ElementFilter.typesIn(enclosedElements); + for (TypeElement innerType : types) { + if ( innerType == null ){ + continue; + } + analyzeType(innerType, typeElement , model , info ); + } + Set enclosedSet = new HashSet( enclosedElements ); + enclosedSet.removeAll( types ); + for(Element element : enclosedSet ){ + if ( element == null ){ + continue; + } + analyze(typeElement, model, element, info ); + } + } + + private void analyze( TypeElement typeElement, WebBeansModel model, + Element element, CompilationInfo info ) + { + ModelAnalyzer analyzer; + if ( isCancelled() ){ + return; + } + analyzer = ANALIZERS.get( element.getKind() ); + if ( analyzer == null ){ + return; + } + analyzer.analyze(element, typeElement, model, getCancel(), getResult()); + } + + private CdiEditorAwareJavaSourceTaskFactory myFactory; + + private static final Map ANALIZERS = + new HashMap(); + + static { + ANALIZERS.put(ElementKind.CLASS, new ClassModelAnalyzer()); + ANALIZERS.put(ElementKind.FIELD, new FieldModelAnalyzer()); + ANALIZERS.put(ElementKind.METHOD, new MethodModelAnalyzer()); + ANALIZERS.put(ElementKind.ANNOTATION_TYPE, new AnnotationModelAnalyzer()); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/WebBeansEditorAnalysisTask.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/WebBeansEditorAnalysisTask.java new file mode 100644 index 000000000000..ef7bd0a7ce5a --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/WebBeansEditorAnalysisTask.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +class WebBeansEditorAnalysisTask extends CancellableAnalysysTask { + + + WebBeansEditorAnalysisTask(FileObject javaFile, + CdiEditorAwareJavaSourceTaskFactory factory ) + { + super( javaFile , factory ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.CancellableAnalysysTask#getLayerName() + */ + @Override + protected String getLayerName() { + return "Web Beans Model Analyzer"; // NOI18N + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.CancellableAnalysysTask#createTask() + */ + @Override + protected AbstractAnalysisTask createTask() { + return new WebBeansAnalysisTask( getFactory() ); + } + + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/WebBeansModelAnalysisFactory.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/WebBeansModelAnalysisFactory.java new file mode 100644 index 000000000000..a5ed362ecc38 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/WebBeansModelAnalysisFactory.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import org.netbeans.api.java.source.CancellableTask; +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.api.java.source.JavaSource.Priority; +import org.netbeans.api.java.source.JavaSourceTaskFactory; +import org.openide.filesystems.FileObject; +import org.openide.util.lookup.ServiceProvider; + + +/** + * @author ads + * + */ +@ServiceProvider(service=JavaSourceTaskFactory.class) +public class WebBeansModelAnalysisFactory extends + CdiEditorAwareJavaSourceTaskFactory +{ + + public WebBeansModelAnalysisFactory( ) { + super(Priority.LOW); + } + + /* (non-Javadoc) + * @see org.netbeans.api.java.source.JavaSourceTaskFactory#createTask(org.openide.filesystems.FileObject) + */ + @Override + protected CancellableTask createTask( FileObject fileObject ) { + return new WebBeansEditorAnalysisTask( fileObject, this ); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AbstractDecoratorAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AbstractDecoratorAnalyzer.java new file mode 100644 index 000000000000..68de8c5c40a9 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AbstractDecoratorAnalyzer.java @@ -0,0 +1,187 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationHelper; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.field.DelegateFieldAnalizer; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public abstract class AbstractDecoratorAnalyzer { + + protected void analyzeDecoratedBeans( DependencyInjectionResult res, + VariableElement element, T t, TypeElement decorator , + WebBeansModel model, Result result ) + { + Set decoratedBeans = null; + if ( res instanceof DependencyInjectionResult.ApplicableResult ){ + DependencyInjectionResult.ApplicableResult appResult = + (DependencyInjectionResult.ApplicableResult) res; + decoratedBeans = appResult.getTypeElements(); + } + else if ( res instanceof DependencyInjectionResult.InjectableResult ){ + Element decorated = ((DependencyInjectionResult.InjectableResult)res). + getElement(); + if ( decorated instanceof TypeElement ){ + decoratedBeans = Collections.singleton( (TypeElement)decorated); + } + } + if ( decoratedBeans == null ){ + return; + } + for( TypeElement decorated : decoratedBeans ){ + Set modifiers = decorated.getModifiers(); + if ( modifiers.contains(Modifier.FINAL)){ + addClassError( element , t , decorated, model , result ); + return; + } + } + if ( decoratedBeans.isEmpty() ){ + return; + } + /* + * The rule : "If a decorator matches a managed bean with a non-static, + * non-private, final method, the decorator shouldn't also implement that method." + * is actually nonsense. + * Each Java class has final wait(). Decorator is also java class + * so it also has a method wait() . So it always implements + * non-static, non-private final method. + * I believe one need to care about ONLY methods in decorated types : + * all methods that are defined in interfaces ( decorated types ) + * and which are implemented in the decorator and decorated bean. + * + * Here is implementation of this requirement. + */ + Collection decoratedTypes = DelegateFieldAnalizer + .getDecoratedTypes(decorator, model.getCompilationController()); + for (TypeMirror typeMirror : decoratedTypes) { + Element decoratedTypeElement = model.getCompilationController() + .getTypes().asElement(typeMirror); + if (!(decoratedTypeElement instanceof TypeElement)) { + continue; + } + TypeElement iface = (TypeElement) decoratedTypeElement; + List methods = ElementFilter.methodsIn(iface + .getEnclosedElements()); + for (ExecutableElement method : methods) { + Element decoratorMethod = model.getCompilationController() + .getElementUtilities() + .getImplementationOf(method, decorator); + if (decoratorMethod == null) { + continue; + } + if (decoratorMethod.getModifiers().contains(Modifier.ABSTRACT)) + { + continue; + } + for (TypeElement decorated : decoratedBeans) { + Element decoratedMethod = model.getCompilationController() + .getElementUtilities() + .getImplementationOf(method, decorated); + if (decoratedMethod == null) { + continue; + } + if (decoratedMethod.getModifiers().contains(Modifier.FINAL)) + { + addMethodError( element , t, decorated, decoratedMethod, + model , result ); + } + } + } + } + } + + protected boolean checkBuiltInBeans( VariableElement element, + TypeMirror elementType, WebBeansModel model, AtomicBoolean cancel ) + { + TypeElement context = model.getCompilationController().getElements(). + getTypeElement(AnnotationUtil.CONTEXT); + if ( context != null && context.equals(model.getCompilationController(). + getTypes().asElement(elementType))) + { + /* This is built-in jakarta.enterprise.context.spi.Context bean + * provided by container for each scope + */ + return true; + } + if ( cancel.get()){ + return true; + } + + Element varElement = model.getCompilationController().getTypes(). + asElement(elementType); + if ( varElement instanceof TypeElement ){ + if ( !((TypeElement)varElement).getQualifiedName().contentEquals( + AnnotationUtil.CONVERSATION)) + { + return false; + } + } + else { + return false; + } + + if ( model.hasImplicitDefaultQualifier( element ) ){ + return true; + } + List qualifiers = model.getQualifiers(element, true); + AnnotationHelper helper = new AnnotationHelper(model.getCompilationController()); + Map qualifiersFqns = helper. + getAnnotationsByType(qualifiers); + boolean hasOnlyDefault = false; + if ( qualifiersFqns.containsKey(AnnotationUtil.DEFAULT_FQN)){ + HashSet fqns = new HashSet(qualifiersFqns.keySet()); + fqns.remove( AnnotationUtil.NAMED ); + fqns.remove( AnnotationUtil.ANY ); + hasOnlyDefault = fqns.size() == 1; + } + return hasOnlyDefault; + } + + protected abstract void addMethodError( VariableElement element, T t, + TypeElement decorated, Element decoratedMethod, + WebBeansModel model, Result result ); + + protected abstract void addClassError( VariableElement element , T t, + TypeElement decoratedBean, WebBeansModel model, Result result ); + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AbstractInterceptedElementAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AbstractInterceptedElementAnalyzer.java new file mode 100644 index 000000000000..61e733ee6437 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AbstractInterceptedElementAnalyzer.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; + +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public abstract class AbstractInterceptedElementAnalyzer { + + + protected Set getInterceptorBindings(Element element, + WebBeansModel model) + { + Collection interceptorBindings = model + .getInterceptorBindings(element); + return new HashSet( interceptorBindings ); + } + + protected boolean hasInterceptorBindings(Element element, + WebBeansModel model ) + { + return !getInterceptorBindings(element, model).isEmpty(); + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AbstractProducerAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AbstractProducerAnalyzer.java new file mode 100644 index 000000000000..efde11dc2877 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AbstractProducerAnalyzer.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer; + +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; + + +/** + * @author ads + * + */ +public abstract class AbstractProducerAnalyzer { + + protected abstract void hasTypeVar( Element element, TypeMirror type, + CdiAnalysisResult result ); + + protected abstract void hasWildCard(Element element, TypeMirror type, + CdiAnalysisResult result); + + protected void checkType( Element element, TypeMirror type, + CdiAnalysisResult result ) + { + if ( type.getKind() == TypeKind.TYPEVAR ){ + hasTypeVar(element, type, result ); + } + else if (hasWildCard(type)) { + hasWildCard( element, type, result ); + return; + } + } + + protected boolean hasType(TypeMirror typeMirror, TypeKind kind ){ + if ( typeMirror instanceof DeclaredType ){ + List typeArguments = + ((DeclaredType)typeMirror).getTypeArguments(); + for (TypeMirror paramType : typeArguments) { + if ( paramType.getKind() == kind ){ + return true; + } + else { + if ( hasType(paramType, kind) ){ + return true; + } + } + } + } + else if ( typeMirror instanceof ArrayType ){ + return hasType( ((ArrayType)typeMirror).getComponentType(), kind); + } + return false; + } + + private boolean hasWildCard(TypeMirror typeMirror){ + return hasType(typeMirror, TypeKind.WILDCARD); + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AbstractScopedAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AbstractScopedAnalyzer.java new file mode 100644 index 000000000000..4ecdf1a8a9aa --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AbstractScopedAnalyzer.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result; +import org.netbeans.modules.jakarta.web.beans.api.model.CdiException; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public abstract class AbstractScopedAnalyzer { + + public void analyzeScope( Element element, + WebBeansModel model, AtomicBoolean cancel , Result result ) + { + try { + String scope = model.getScope( element ); + if ( cancel.get() ){ + return; + } + TypeElement scopeElement = model.getCompilationController(). + getElements().getTypeElement( scope ); + if ( scopeElement == null ){ + return; + } + checkScope( scopeElement , element , model, cancel, result ); + } + catch (CdiException e) { + result.requireCdiEnabled(element, model); + informCdiException(e, element, model, result ); + } + } + + protected abstract void checkScope( TypeElement scopeElement, Element element, + WebBeansModel model, AtomicBoolean cancel, Result result ); + + protected boolean hasTypeVarParameter(TypeMirror type ){ + if ( type.getKind() == TypeKind.TYPEVAR){ + return true; + } + if ( type instanceof DeclaredType ){ + List typeArguments = + ((DeclaredType)type).getTypeArguments(); + for (TypeMirror typeArg : typeArguments) { + if ( hasTypeVarParameter(typeArg)){ + return true; + } + } + } + else if ( type instanceof ArrayType ){ + return hasTypeVarParameter(((ArrayType)type).getComponentType()); + } + return false; + } + + protected boolean isPassivatingScope( TypeElement scope, WebBeansModel model ) { + AnnotationMirror normalScope = AnnotationUtil.getAnnotationMirror( + scope, model.getCompilationController(), AnnotationUtil.NORMAL_SCOPE_FQN); + if ( normalScope==null){ + return false; + } + Map elementValues = + normalScope.getElementValues(); + boolean isPassivating = false; + for (Entry entry: + elementValues.entrySet()) + { + ExecutableElement key = entry.getKey(); + if ( key.getSimpleName().contentEquals(AnnotationUtil.PASSIVATING)){ + isPassivating = Boolean.TRUE.toString().equals(entry.getValue().toString()); + } + } + return isPassivating; + } + + protected boolean isSerializable( Element element, WebBeansModel model ) { + TypeMirror elementType = element.asType(); + if ( elementType == null || elementType.getKind() == TypeKind.ERROR){ + return true; + } + return isSerializable(elementType, model); + } + + protected boolean isSerializable( TypeMirror type, WebBeansModel model ) { + TypeElement serializable = model.getCompilationController().getElements(). + getTypeElement(Serializable.class.getCanonicalName()); + if ( serializable == null ){ + return true; + } + TypeMirror serializableType = serializable.asType(); + if ( serializableType == null || serializableType.getKind() == TypeKind.ERROR){ + return true; + } + return model.getCompilationController().getTypes().isSubtype(type, + serializableType); + } + + private void informCdiException(CdiException exception , Element element, + WebBeansModel model, Result result ) + { + result.addError( element, model, exception.getMessage()); + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AbstractTypedAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AbstractTypedAnalyzer.java new file mode 100644 index 000000000000..bc05fd57e19e --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AbstractTypedAnalyzer.java @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; + + +/** + * @author ads + * + */ +public abstract class AbstractTypedAnalyzer { + + public void analyze( Element element, TypeMirror elementType, + AtomicBoolean cancel , CdiAnalysisResult result ) + { + CompilationInfo compInfo = result.getInfo(); + List list = getRestrictedTypes(element, compInfo, cancel); + if ( list == null ){ + return; + } + result.requireCdiEnabled(element); + for (TypeMirror type : list) { + if ( cancel.get()){ + return; + } + boolean isSubtype = hasBeanType(element, elementType, type, compInfo); + if (!isSubtype) { + addError(element, result ); + } + } + // check @Specializes types restriction conformance + if ( cancel.get()){ + return; + } + if ( AnnotationUtil.hasAnnotation(element, AnnotationUtil.SPECIALIZES, + compInfo)) + { + result.requireCdiEnabled(element); + checkSpecializes( element , elementType , list, cancel , result ); + } + } + + protected abstract void checkSpecializes( Element element, TypeMirror elementType, + List restrictedTypes, AtomicBoolean cancel , CdiAnalysisResult result ); + + protected boolean hasBeanType( Element subject, TypeMirror elementType, + TypeMirror requiredBeanType,CompilationInfo compInfo ) + { + return compInfo.getTypes().isSubtype(elementType, requiredBeanType); + } + + protected abstract void addError ( Element element , + CdiAnalysisResult result ); + + protected void collectAncestors(TypeElement type , Set ancestors, + CompilationInfo compInfo ) + { + TypeMirror superclass = type.getSuperclass(); + addAncestor( superclass, ancestors, compInfo); + List interfaces = type.getInterfaces(); + for (TypeMirror interfaze : interfaces) { + addAncestor(interfaze, ancestors, compInfo); + } + } + + private void addAncestor( TypeMirror parent , Set ancestors, + CompilationInfo compInfo) + { + if ( parent == null ){ + return; + } + Element parentElement = compInfo.getTypes().asElement( parent ); + if ( parentElement instanceof TypeElement ){ + if ( ancestors.contains( (TypeElement)parentElement)) + { + return; + } + ancestors.add( (TypeElement)parentElement); + collectAncestors((TypeElement)parentElement, ancestors, compInfo); + } + } + + protected List getRestrictedTypes(Element element, + CompilationInfo compInfo , AtomicBoolean cancel) + { + AnnotationMirror typedMirror = AnnotationUtil.getAnnotationMirror(element, + AnnotationUtil.TYPED, compInfo); + if ( typedMirror == null ){ + return null; + } + Map values = + typedMirror.getElementValues(); + AnnotationValue restrictedTypes = null; + for (Entry entry : + values.entrySet() ) + { + ExecutableElement key = entry.getKey(); + AnnotationValue value = entry.getValue(); + if ( AnnotationUtil.VALUE.contentEquals(key.getSimpleName())){ + restrictedTypes = value; + break; + } + } + if ( restrictedTypes == null ){ + return Collections.emptyList(); + } + if ( cancel.get() ){ + return Collections.emptyList(); + } + Object value = restrictedTypes.getValue(); + if ( value instanceof List ){ + List result = new ArrayList(((List)value).size()); + for( Object type : (List)value){ + AnnotationValue annotationValue = (AnnotationValue)type; + type = annotationValue.getValue(); + if (type instanceof TypeMirror){ + result.add( (TypeMirror)type); + } + } + return result; + } + return Collections.emptyList(); + } + + protected Set getUnrestrictedBeanTypes( TypeElement element, + CompilationInfo compInfo) + { + Set set = new HashSet(); + set.add( element ); + collectAncestors(element, set, compInfo); + return set; + } + + protected Set getElements( Collection types , + CompilationInfo info ) + { + Set result = new HashSet(); + for (TypeMirror typeMirror : types) { + Element element = info.getTypes().asElement(typeMirror); + if ( element instanceof TypeElement ){ + result.add( (TypeElement)element); + } + } + return result; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AnnotationElementAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AnnotationElementAnalyzer.java new file mode 100644 index 000000000000..f80dccb6a85c --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AnnotationElementAnalyzer.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.InterceptorBindingMembersAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.QualifierAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.ScopeAnalyzer; + + +/** + * @author ads + * + */ +public class AnnotationElementAnalyzer implements ElementAnalyzer { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.ElementAnalyzer#analyze(javax.lang.model.element.Element, javax.lang.model.element.TypeElement, org.netbeans.api.java.source.CompilationInfo, java.util.List, java.util.concurrent.atomic.AtomicBoolean) + */ + @Override + public void analyze( Element element, TypeElement parent, + AtomicBoolean cancel, CdiAnalysisResult result ) + { + TypeElement subject = (TypeElement) element; + for( AnnotationAnalyzer analyzer : ANALYZERS ){ + if ( cancel.get() ){ + return; + } + analyzer.analyze( subject, cancel , result ); + } + } + + public interface AnnotationAnalyzer { + public static final String INCORRECT_RUNTIME = "ERR_IncorrectRuntimeRetention"; //NOI18N + + void analyze( TypeElement element , AtomicBoolean cancel, + CdiAnalysisResult result ); + } + + private static final List ANALYZERS = + new LinkedList(); + + static { + ANALYZERS.add( new ScopeAnalyzer() ); + ANALYZERS.add( new QualifierAnalyzer() ); + ANALYZERS.add( new InterceptorBindingMembersAnalyzer() ); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AnnotationModelAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AnnotationModelAnalyzer.java new file mode 100644 index 000000000000..f5518d8cb18b --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AnnotationModelAnalyzer.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.InterceptorBindingAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.StereotypeAnalyzer; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class AnnotationModelAnalyzer implements ModelAnalyzer { + + @Override + public void analyze( Element element, TypeElement parent, + WebBeansModel model, AtomicBoolean cancel, + Result result ) + { + TypeElement subject = (TypeElement) element; + for( AnnotationAnalyzer analyzer : ANALYZERS ){ + if ( cancel.get() ){ + return; + } + analyzer.analyze( subject, model, cancel, result ); + } + } + + public interface AnnotationAnalyzer { + public static final String INCORRECT_RUNTIME = "ERR_IncorrectRuntimeRetention"; //NOI18N + + void analyze( TypeElement element , WebBeansModel model, + AtomicBoolean cancel, + Result result ); + } + + private static final List ANALYZERS = + new LinkedList(); + + static { + ANALYZERS.add( new StereotypeAnalyzer()); + ANALYZERS.add( new InterceptorBindingAnalyzer() ); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AnnotationUtil.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AnnotationUtil.java new file mode 100644 index 000000000000..c8436b029fce --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/AnnotationUtil.java @@ -0,0 +1,217 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.Elements; + +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public final class AnnotationUtil { + + public static final String ANY = "jakarta.enterprise.inject.Any"; // NOI18N + + public static final String VALUE = "value"; // NOI18N + + public static final String INJECT = "Inject"; // NOI18N + + public static final String INJECT_FQN = "jakarta.inject."+INJECT; // NOI18N + + public static final String DECORATOR = "jakarta.decorator.Decorator"; // NOI18N + + public static final String PRODUCES = "Produces"; + + public static final String PRODUCES_FQN = "jakarta.enterprise.inject."+ // NOI18N + PRODUCES; + + public static final String INTERCEPTOR_BINDING = "InterceptorBinding"; // NOI18N + + public static final String INTERCEPTOR_BINDING_FQN + = "jakarta.interceptor."+INTERCEPTOR_BINDING; // NOI18N + + public static final String INTERCEPTOR = "jakarta.interceptor.Interceptor"; // NOI18N + + public static final String NORMAL_SCOPE = "NormalScope"; // NOI18N + + public static final String NORMAL_SCOPE_FQN + = "jakarta.enterprise.context."+NORMAL_SCOPE;// NOI18N + + public static final String SCOPE = "Scope"; // NOI18N + + public static final String SCOPE_FQN = "jakarta.inject."+SCOPE; // NOI18N + + public static final String REQUEST_SCOPE_FQN = "jakarta.enterprise.context.RequestScoped";// NOI18N + public static final String SESSION_SCOPE_FQN = "jakarta.enterprise.context.SessionScoped";// NOI18N + public static final String APPLICATION_SCOPE_FQN = "jakarta.enterprise.context.ApplicationScoped";// NOI18N + public static final String CONVERSATION_SCOPE_FQN = "jakarta.enterprise.context.ConversationScoped";// NOI18N + public static final String DEPENDENT_SCOPE_FQN = "jakarta.enterprise.context.Dependent";// NOI18N + + + public static final String DISPOSES = "Disposes"; // NOI18N + + public static final String DISPOSES_FQN = "jakarta.enterprise.inject."+ // NOI18N + DISPOSES; + + public static final String OBSERVES = "Observes"; // NOI18N + + public static final String OBSERVES_FQN = "jakarta.enterprise.event."+ // NOI18N + OBSERVES; + + public static final String STATELESS = "jakarta.ejb.Stateless"; // NOI18N + + public static final String STATEFUL = "jakarta.ejb.Stateful"; // NOI18N + + public static final String SINGLETON = "jakarta.ejb.Singleton"; // NOI18N + public static final String CDISINGLETON = "jakarta.inject.Singleton"; // NOI18N + + public static final String APPLICATION_SCOPED + = "jakarta.enterprise.context.ApplicationScoped"; // NOI18N + + public static final String DEPENDENT + = "jakarta.enterprise.context.Dependent"; // NOI18N + + public static final String STEREOTYPE = "Stereotype"; // NOI18N + + public static final String STEREOTYPE_FQN = + "jakarta.enterprise.inject."+STEREOTYPE; // NOI18N + + public static final String NAMED = "jakarta.inject.Named"; // NOI18N + + public static final String QUALIFIER = "Qualifier"; // NOI18N + + public static final String QUALIFIER_FQN= + "jakarta.inject."+QUALIFIER; // NOI18N + + public static final String DELEGATE_FQN = + "jakarta.decorator.Delegate"; // NOI18N + + public static final String SPECIALIZES = "jakarta.enterprise.inject.Specializes"; // NOI18N + + public static final String INJECTION_POINT = + "jakarta.enterprise.inject.spi.InjectionPoint"; // NOI18N + + public static final String DEFAULT_FQN = "jakarta.enterprise.inject.Default"; // NOI18N + + public static final String POST_CONSTRUCT = "jakarta.annotation.PostConstruct"; // NOI18N + + public static final String PRE_DESTROY = "jakarta.annotation.PreDestroy"; // NOI18N + + public static final String POST_ACTIVATE = "jakarta.ejb.PostActivate"; // NOI18N + + public static final String PRE_PASSIVATE = "jakarta.ejb.PrePassivate"; // NOI18N + + public static final String CONTEXT = "jakarta.enterprise.context.spi.Context"; // NOI18N + + public static final String CONVERSATION = "jakarta.enterprise.context.Conversation";// NOI18N + + public static final String ALTERNATVE = "jakarta.enterprise.inject.Alternative"; // NOI18N + + public static final String TYPED = "jakarta.enterprise.inject.Typed"; // NOI18N + + public static final String NON_BINDING = "jakarta.enterprise.util.Nonbinding"; // NOI18N + + public static final String PASSIVATING = "passivating"; // NOI18N + + public static final String PROVIDER = "jakarta.inject.Provider";// NOI18N + + private AnnotationUtil(){ + } + + public static boolean hasAnnotation(Element element, String annotation, + CompilationInfo info ) + { + return getAnnotationMirror(element, annotation, info)!=null; + } + + public static AnnotationMirror getAnnotationMirror(Element element, + String annotation,CompilationInfo info ) + { + return getAnnotationMirror(element, info, annotation); + } + + /** + * return AnnotationMirror for first found annotation from annotationFqns + * @param element + * @param info + * @param annotationFqns + * @return + */ + public static AnnotationMirror getAnnotationMirror(Element element, + CompilationInfo info , String... annotationFqns) + { + Set set = new HashSet(); + Elements els = info.getElements(); + for( String annotation : annotationFqns){ + TypeElement annotationElement = els.getTypeElement( + annotation); + if ( annotationElement != null ){ + set.add( annotationElement ); + } + } + + List annotations = + els.getAllAnnotationMirrors( element ); + for (AnnotationMirror annotationMirror : annotations) { + Element declaredAnnotation = info.getTypes().asElement( + annotationMirror.getAnnotationType()); + if ( set.contains( declaredAnnotation ) ){ + return annotationMirror; + } + } + return null; + } + + public static boolean isSessionBean(Element element , + CompilationInfo compInfo ) + { + return getAnnotationMirror(element, compInfo, STATEFUL, STATELESS, + SINGLETON)!= null; + } + + public static boolean isDelegate(Element element, TypeElement parent, + WebBeansModel model ) + { + return AnnotationUtil.hasAnnotation(element, + AnnotationUtil.DELEGATE_FQN, model.getCompilationController()) + && AnnotationUtil.hasAnnotation( parent, + AnnotationUtil.DECORATOR, model.getCompilationController()); + } + + public static boolean isLifecycleCallback( ExecutableElement element , + CompilationInfo info ) + { + AnnotationMirror annotationMirror = getAnnotationMirror(element, info, + POST_ACTIVATE, POST_CONSTRUCT , PRE_DESTROY, PRE_PASSIVATE); + return annotationMirror != null; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/Bundle.properties b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/Bundle.properties new file mode 100644 index 000000000000..2fcfd0daeb80 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/Bundle.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +ERR_BadAnnotationParamCtor=A bean constructor should not have a parameter annotated @{0}. \ No newline at end of file diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/ClassElementAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/ClassElementAnalyzer.java new file mode 100644 index 000000000000..d054c4b97540 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/ClassElementAnalyzer.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.type.AnnotationsAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.type.CtorsAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.type.TypedClassAnalizer; + + +/** + * @author ads + * + */ +public class ClassElementAnalyzer implements ElementAnalyzer { + + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.ElementAnalyzer#analyze(javax.lang.model.element.Element, javax.lang.model.element.TypeElement, org.netbeans.api.java.source.CompilationInfo, java.util.List, java.util.concurrent.atomic.AtomicBoolean) + */ + @Override + public void analyze( Element element, TypeElement parent, + AtomicBoolean cancel, CdiAnalysisResult result ) + { + TypeElement subject = (TypeElement) element; + for( ClassAnalyzer analyzer : ANALYZERS ){ + if ( cancel.get() ){ + return; + } + analyzer.analyze( subject, parent, cancel, result ); + } + } + + public interface ClassAnalyzer { + void analyze( TypeElement element , TypeElement parent, AtomicBoolean cancel, + CdiAnalysisResult result ); + } + + private static final List ANALYZERS= new LinkedList(); + + static { + ANALYZERS.add( new TypedClassAnalizer() ); + ANALYZERS.add( new AnnotationsAnalyzer()); + ANALYZERS.add( new CtorsAnalyzer() ); + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/ClassModelAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/ClassModelAnalyzer.java new file mode 100644 index 000000000000..5619878d45dd --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/ClassModelAnalyzer.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.type.DeclaredIBindingsAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.type.InterceptedBeanAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.type.ManagedBeansAnalizer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.type.NamedModelAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.type.ScopedBeanAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.type.SessionBeanAnalyzer; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class ClassModelAnalyzer implements ModelAnalyzer { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer#analyze(javax.lang.model.element.Element, javax.lang.model.element.TypeElement, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.util.List, java.util.concurrent.atomic.AtomicBoolean) + */ + @Override + public void analyze( Element element, TypeElement parent, + WebBeansModel model, AtomicBoolean cancel, + Result result ) + { + TypeElement subject = (TypeElement) element; + for( ClassAnalyzer analyzer : ANALYZERS ){ + if ( cancel.get() ){ + return; + } + analyzer.analyze( subject, parent, model, cancel, result); + } + } + + public interface ClassAnalyzer { + void analyze( TypeElement element , TypeElement parent, + WebBeansModel model,AtomicBoolean cancel, + Result result ); + } + + private static final List ANALYZERS= new LinkedList(); + + static { + ANALYZERS.add( new ManagedBeansAnalizer()); + ANALYZERS.add( new ScopedBeanAnalyzer()); + ANALYZERS.add( new SessionBeanAnalyzer()); + ANALYZERS.add( new InterceptedBeanAnalyzer() ); + ANALYZERS.add( new NamedModelAnalyzer() ); + ANALYZERS.add( new DeclaredIBindingsAnalyzer()); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/CtorAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/CtorAnalyzer.java new file mode 100644 index 000000000000..2be7b4474e40 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/CtorAnalyzer.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; + +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class CtorAnalyzer implements ElementAnalyzer { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.ElementAnalyzer#analyze(javax.lang.model.element.Element, javax.lang.model.element.TypeElement, org.netbeans.api.java.source.CompilationInfo, java.util.List, java.util.concurrent.atomic.AtomicBoolean) + */ + @Override + public void analyze( Element element, TypeElement parent, + AtomicBoolean cancel, CdiAnalysisResult result ) + { + ExecutableElement ctor = (ExecutableElement)element; + List parameters = ctor.getParameters(); + for (VariableElement param : parameters) { + if ( cancel.get() ){ + return; + } + boolean isDisposer = AnnotationUtil.hasAnnotation(param, + AnnotationUtil.DISPOSES_FQN, result.getInfo()); + boolean isObserver = AnnotationUtil.hasAnnotation(param, + AnnotationUtil.OBSERVES_FQN, result.getInfo()); + if ( isDisposer || isObserver ){ + result.requireCdiEnabled(element); + String annotation = isDisposer ? AnnotationUtil.DISPOSES : + AnnotationUtil.OBSERVES; + result.addError( element, NbBundle.getMessage( + CtorAnalyzer.class, "ERR_BadAnnotationParamCtor", annotation)); // NOI18N + break; + } + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/ElementAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/ElementAnalyzer.java new file mode 100644 index 000000000000..05f042d51dd6 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/ElementAnalyzer.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer; + +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; + + +/** + * @author ads + * + */ +public interface ElementAnalyzer { + + void analyze( Element element , TypeElement parent, AtomicBoolean cancel, + CdiAnalysisResult result ); + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/FieldElementAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/FieldElementAnalyzer.java new file mode 100644 index 000000000000..406509e67b12 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/FieldElementAnalyzer.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.field.DelegateFieldAnalizer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.field.ProducerFieldAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.field.TypedFieldAnalyzer; + + +/** + * @author ads + * + */ +public class FieldElementAnalyzer implements ElementAnalyzer { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer#analyze(javax.lang.model.element.Element, javax.lang.model.element.TypeElement, java.util.concurrent.atomic.AtomicBoolean, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer.Result) + */ + @Override + public void analyze( Element element, TypeElement parent, + AtomicBoolean cancel, CdiAnalysisResult result ) + { + VariableElement var = (VariableElement) element; + TypeMirror varType = result.getInfo().getTypes().asMemberOf( + (DeclaredType)parent.asType(), var ); + for (FieldAnalyzer analyzer : ANALYZERS) { + if ( cancel.get()){ + return; + } + analyzer.analyze(var, varType, parent, cancel, result ); + } + } + + public interface FieldAnalyzer { + void analyze( VariableElement element , TypeMirror elementType, + TypeElement parent, AtomicBoolean cancel, + CdiAnalysisResult result ); + } + + private static final List ANALYZERS= new LinkedList(); + + static { + ANALYZERS.add( new TypedFieldAnalyzer() ); + ANALYZERS.add( new DelegateFieldAnalizer()); + ANALYZERS.add( new ProducerFieldAnalyzer()); + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/FieldModelAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/FieldModelAnalyzer.java new file mode 100644 index 000000000000..e8f5ca6a8a6e --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/FieldModelAnalyzer.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.field.InjectionPointAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.field.ScopedFieldAnalyzer; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class FieldModelAnalyzer implements ModelAnalyzer { + + @Override + public void analyze( Element element, TypeElement parent, + WebBeansModel model, AtomicBoolean cancel, + Result result ) + { + VariableElement var = (VariableElement) element; + if ( cancel.get()){ + return; + } + TypeMirror varType = model.getCompilationController().getTypes().asMemberOf( + (DeclaredType)parent.asType(), var ); + for (FieldAnalyzer analyzer : ANALYZERS) { + if ( cancel.get()){ + return; + } + analyzer.analyze(var, varType, parent, model, cancel, result ); + } + } + + public interface FieldAnalyzer { + void analyze( VariableElement element , TypeMirror elementType, + TypeElement parent, WebBeansModel model, + AtomicBoolean cancel, Result result ); + } + + private static final List ANALYZERS= new LinkedList(); + + static { + ANALYZERS.add( new ScopedFieldAnalyzer() ); + ANALYZERS.add( new InjectionPointAnalyzer()); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/MethodElementAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/MethodElementAnalyzer.java new file mode 100644 index 000000000000..fd7e08f9ccb9 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/MethodElementAnalyzer.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.method.AnnotationsAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.method.DelegateMethodAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.method.ProducerMethodAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.method.TypedMethodAnalyzer; + + +/** + * @author ads + * + */ +public class MethodElementAnalyzer implements ElementAnalyzer { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer#analyze(javax.lang.model.element.Element, javax.lang.model.element.TypeElement, java.util.concurrent.atomic.AtomicBoolean, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer.Result) + */ + @Override + public void analyze( Element element, TypeElement parent, + AtomicBoolean cancel, CdiAnalysisResult result ) + { + ExecutableElement method = (ExecutableElement) element; + TypeMirror methodType = result.getInfo().getTypes().asMemberOf( + (DeclaredType)parent.asType(), method ); + if ( methodType instanceof ExecutableType ){ + if ( cancel.get()){ + return; + } + TypeMirror returnType = ((ExecutableType) methodType).getReturnType(); + for (MethodAnalyzer analyzer : ANALYZERS) { + if ( cancel.get() ){ + return; + } + analyzer.analyze(method, returnType, parent, cancel, + result ); + } + } + } + + public interface MethodAnalyzer { + void analyze( ExecutableElement element , TypeMirror returnType, + TypeElement parent, AtomicBoolean cancel , CdiAnalysisResult result ); + } + + private static final List ANALYZERS= new LinkedList(); + + static { + ANALYZERS.add( new TypedMethodAnalyzer() ); + ANALYZERS.add( new AnnotationsAnalyzer() ); + ANALYZERS.add( new DelegateMethodAnalyzer() ); + ANALYZERS.add( new ProducerMethodAnalyzer() ); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/MethodModelAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/MethodModelAnalyzer.java new file mode 100644 index 000000000000..d8e96fe62d8c --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/MethodModelAnalyzer.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.method.InjectionPointParameterAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.method.InterceptedMethodAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.method.ScopedMethodAnalyzer; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class MethodModelAnalyzer implements ModelAnalyzer { + + @Override + public void analyze( Element element, TypeElement parent, + WebBeansModel model, AtomicBoolean cancel, + Result result ) + { + ExecutableElement method = (ExecutableElement) element; + TypeMirror methodType = model.getCompilationController().getTypes(). + asMemberOf( (DeclaredType)parent.asType(), method ); + if ( methodType instanceof ExecutableType ){ + if ( cancel.get()){ + return; + } + TypeMirror returnType = ((ExecutableType) methodType).getReturnType(); + for (MethodAnalyzer analyzer : ANALYZERS) { + if ( cancel.get() ){ + return; + } + analyzer.analyze(method, returnType, parent, model, + cancel, result ); + } + } + } + + public interface MethodAnalyzer { + void analyze( ExecutableElement element , TypeMirror returnType, + TypeElement parent, WebBeansModel model, + AtomicBoolean cancel , Result result); + } + + private static final List ANALYZERS= new LinkedList(); + + static { + ANALYZERS.add( new ScopedMethodAnalyzer() ); + ANALYZERS.add( new InjectionPointParameterAnalyzer() ); + ANALYZERS.add( new InterceptedMethodAnalyzer() ); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/ModelAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/ModelAnalyzer.java new file mode 100644 index 000000000000..dda42f87590c --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/ModelAnalyzer.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer; + +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; + +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.CdiEditorAnalysisFactory; +import org.netbeans.modules.jakarta.web.beans.analysis.CdiEditorAwareJavaSourceTaskFactory; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.spi.editor.hints.ErrorDescription; +import org.netbeans.spi.editor.hints.Severity; + + +/** + * @author ads + * + */ +public interface ModelAnalyzer { + + void analyze( Element element , TypeElement parent, WebBeansModel model, + AtomicBoolean cancel, Result result ); + + public class Result extends CdiAnalysisResult { + + public Result( CompilationInfo info , + CdiEditorAwareJavaSourceTaskFactory factory ) + { + super(info, factory); + } + + public void addNotification( Severity severity, Element element, + WebBeansModel model, String message ) + { + ErrorDescription description = CdiEditorAnalysisFactory. + createNotification( severity, element, model, getInfo() , + message); + if ( description == null ){ + return; + } + getProblems().add( description ); + } + + public void addNotification( Severity severity, + VariableElement element, ExecutableElement method, + WebBeansModel model, String message ) + { + ErrorDescription description = CdiEditorAnalysisFactory. + createNotification( severity, element,method, model, getInfo() , + message); + if ( description == null ){ + return; + } + getProblems().add( description ); + } + + public void addError( Element element, + WebBeansModel model, String message ) + { + addNotification(Severity.ERROR, element, model, message); + } + + public void addError( VariableElement var, ExecutableElement element, + WebBeansModel model, String message ) + { + addNotification(Severity.ERROR, var, element, model, message); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult#addError(javax.lang.model.element.Element, java.lang.String) + */ + @Override + public void addError( Element subject, String message ) { + ErrorDescription description = CdiEditorAnalysisFactory. + createNotification( Severity.ERROR, subject, getInfo() , + message); + if ( description == null ){ + return; + } + getProblems().add( description ); + } + + public void requireCdiEnabled( Element element , WebBeansModel model){ + ElementHandle handle = ElementHandle.create(element); + Element resolved = handle.resolve( getInfo() ); + if ( resolved == null ){ + return; + } + requireCdiEnabled( resolved ); + } + + public void requireCdiEnabled( VariableElement element , + ExecutableElement method ,WebBeansModel model) + { + VariableElement resolved = CdiEditorAnalysisFactory. + resolveParameter(element, method, getInfo()); + if ( resolved == null ){ + return; + } + requireCdiEnabled( resolved ); + } + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/Bundle.properties b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/Bundle.properties new file mode 100644 index 000000000000..d1b1b910987c --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/Bundle.properties @@ -0,0 +1,46 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +ERR_NonEmptyNamedStereotype=A stereotype should not declare a non-empty @Named annotation. +ERR_IncorrectRuntimeRetention=The CDI annotation should be defined with @Retention(RUNTIME). +ERR_NoTarget=The CDI annotation is defined with @{0} but has no @Target. +ERR_NoRetention=The CDI annotation is defined with @{0} but has no @Retention. +ERR_IncorrectScopeTarget=The CDI annotation is declared as Scope but has wrong target \ +value. Correct target values is '{METHOD, FIELD, TYPE'}. +ERR_IncorrectInterceptorBindingTarget=The CDI Annotation is declared as Interceptor \ +Binding but it has wrong target values. Correct target values are '{METHOD, TYPE'} or TYPE. +ERR_IncorrectStereotypeTarget=The CDI Annotation is declared as Stereotype but it has \ +wrong target values. Correct target values are are '{METHOD, FIELD, TYPE'} or \ +'{METHOD, FIELD'} or TYPE or METHOD or FIELD. +ERR_IncorrectQualifierTarget=The CDI Annotation is declared as Qualifier but it \ +has wrong target values. Correct target values are \ +'{METHOD, FIELD, PARAMETER, TYPE'} or '{FIELD, PARAMETER'}. +ERR_IncorrectTargetWithInterceptorBindings=A stereotype with interceptor binding \ +declared must be defined as @Target(TYPE). +ERR_IncorrectTransitiveInterceptorBinding=Interceptor binding is defined as \ +@Target('{TYPE, METHOD'}) and declares interceptor binding {0} which is defined as \ +@Target(TYPE). +ERR_IncorrectTransitiveTarget=Stereotypes @{0} declared @Target('{TYPE'}) and may not \ +be applied to stereotypes declared @Target('{TYPE, METHOD, FIELD'}), @Target('{METHOD'}), \ +@Target('{FIELD'}) or @Target('{METHOD, FIELD'}). +WARN_QualifiedStereotype=A stereotype should not declare any qualifier annotation \ +other than @Named. Otherwise non-portable behavior results. +WARN_TypedStereotype=A stereotype should not be annotated @Typed. Otherwise non-portable behavior results. +WARN_ArrayAnnotationValuedQualifierMember=Array-valued or annotation-valued members \ +of a qualifier type should be annotated @Nonbinding. Otherwise non-portable behavior results. +WARN_ArrayAnnotationValuedIBindingMember=Array-valued or annotation-valued members of \ +an interceptor binding type should be annotated @Nonbinding. Otherwise non-portable behavior results. \ No newline at end of file diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/CdiAnnotationAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/CdiAnnotationAnalyzer.java new file mode 100644 index 000000000000..3f014c227496 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/CdiAnnotationAnalyzer.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +abstract class CdiAnnotationAnalyzer extends TargetAnalyzer { + + CdiAnnotationAnalyzer(TypeElement element, CdiAnalysisResult result ) + { + init( element , result.getInfo() ); + myResult =result; + } + + CdiAnnotationAnalyzer(TypeElement element, WebBeansModel model, + CdiAnalysisResult result ) + { + init( element , model.getCompilationController() ); + myModel = model; + myResult =result; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.annotation.TargetAnalyzer#handleNoTarget() + */ + @Override + protected void handleNoTarget() { + if ( myResult== null){ + return; + } + Element subject = getElement(); + if ( myModel != null ){ + ElementHandle handle = ElementHandle.create( getElement()); + subject = handle.resolve(getResult().getInfo()); + } + if ( subject == null ){ + return; + } + myResult.addError( subject, NbBundle.getMessage(ScopeAnalyzer.class, + "ERR_NoTarget" , // NOI18N + getCdiMetaAnnotation())); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.annotation.RuntimeRetentionAnalyzer#handleNoRetention() + */ + @Override + protected void handleNoRetention() { + if ( myResult== null){ + return; + } + Element subject = getElement(); + if ( myModel != null ){ + ElementHandle handle = ElementHandle.create( getElement()); + subject = handle.resolve(getResult().getInfo()); + } + if ( subject == null ){ + return; + } + myResult.addError( subject, NbBundle.getMessage(ScopeAnalyzer.class, + "ERR_NoRetention", // NOI18N + getCdiMetaAnnotation())); + } + + protected abstract String getCdiMetaAnnotation(); + + protected CdiAnalysisResult getResult(){ + return myResult; + } + + private WebBeansModel myModel; + private CdiAnalysisResult myResult; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/InterceptorBindingAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/InterceptorBindingAnalyzer.java new file mode 100644 index 000000000000..acb4181c2b9b --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/InterceptorBindingAnalyzer.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation; + +import java.lang.annotation.ElementType; +import java.util.Collection; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationHelper; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationModelAnalyzer.AnnotationAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class InterceptorBindingAnalyzer implements AnnotationAnalyzer { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationModelAnalyzer.AnnotationAnalyzer#analyze(javax.lang.model.element.TypeElement, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.util.List, org.netbeans.api.java.source.CompilationInfo, java.util.concurrent.atomic.AtomicBoolean) + */ + @Override + public void analyze( TypeElement element, WebBeansModel model, + AtomicBoolean cancel , + Result result ) + { + if ( !AnnotationUtil.hasAnnotation(element, + AnnotationUtil.INTERCEPTOR_BINDING_FQN , model.getCompilationController())) + { + return; + } + result.requireCdiEnabled(element, model); + InterceptorTargetAnalyzer analyzer = new InterceptorTargetAnalyzer( + element, model, result ); + if ( cancel.get() ){ + return; + } + if (!analyzer.hasRuntimeRetention()) { + result.addError(element, model, + NbBundle.getMessage(InterceptorBindingAnalyzer.class, + INCORRECT_RUNTIME)); + } + if ( cancel.get() ){ + return; + } + if (!analyzer.hasTarget()) { + result.addError(element, model, + NbBundle.getMessage(InterceptorBindingAnalyzer.class, + "ERR_IncorrectInterceptorBindingTarget")); // NOI18N + } + else { + if ( cancel.get() ){ + return; + } + Set declaredTargetTypes = analyzer.getDeclaredTargetTypes(); + if ( cancel.get() ){ + return; + } + checkTransitiveInterceptorBindings( element, declaredTargetTypes, + model , result ); + } + } + + private void checkTransitiveInterceptorBindings( TypeElement element, + Set declaredTargetTypes, WebBeansModel model, + Result result ) + { + if (declaredTargetTypes == null || declaredTargetTypes.size() == 1) { + return; + } + Collection interceptorBindings = model + .getInterceptorBindings(element); + for (AnnotationMirror iBinding : interceptorBindings) { + Element binding = iBinding.getAnnotationType().asElement(); + if (!(binding instanceof TypeElement)) { + continue; + } + Set bindingTargetTypes = TargetAnalyzer + .getDeclaredTargetTypes( + new AnnotationHelper(model + .getCompilationController()), + (TypeElement) binding); + if (bindingTargetTypes.size() == 1 + && bindingTargetTypes.contains(ElementType.TYPE)) + { + result.addError(element, model , + NbBundle.getMessage(InterceptorBindingAnalyzer.class, + "ERR_IncorrectTransitiveInterceptorBinding", // NOI18N + ((TypeElement) binding).getQualifiedName().toString())); + } + + } + } + + private static class InterceptorTargetAnalyzer extends CdiAnnotationAnalyzer { + + InterceptorTargetAnalyzer( TypeElement element , WebBeansModel model , + Result result) + { + super( element, model , result ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.annotation.CdiAnnotationAnalyzer#getCdiMetaAnnotation() + */ + @Override + protected String getCdiMetaAnnotation() { + return AnnotationUtil.INTERCEPTOR_BINDING; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.annotation.TargetAnalyzer#getTargetVerifier() + */ + @Override + protected TargetVerifier getTargetVerifier() { + return InterceptorBindingVerifier.getInstance(); + } + + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/InterceptorBindingMembersAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/InterceptorBindingMembersAnalyzer.java new file mode 100644 index 000000000000..30bb55d24b44 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/InterceptorBindingMembersAnalyzer.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; + +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationElementAnalyzer.AnnotationAnalyzer; +import org.openide.util.NbBundle; +import org.netbeans.spi.editor.hints.Severity; + + + +/** + * @author ads + * + */ +public class InterceptorBindingMembersAnalyzer implements AnnotationAnalyzer { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationElementAnalyzer.AnnotationAnalyzer#analyze(javax.lang.model.element.TypeElement, java.util.concurrent.atomic.AtomicBoolean, org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult) + */ + @Override + public void analyze( TypeElement element, AtomicBoolean cancel, + CdiAnalysisResult result ) + { + if ( AnnotationUtil.hasAnnotation(element, AnnotationUtil.INTERCEPTOR_BINDING_FQN, + result.getInfo())) + { + checkMembers(element, result, NbBundle.getMessage( + QualifierAnalyzer.class, + "WARN_ArrayAnnotationValuedIBindingMember")); // NOI18N + } + } + + protected void checkMembers( TypeElement element, CdiAnalysisResult result , + String localizedWarning ) + { + List methods = ElementFilter.methodsIn( + element.getEnclosedElements()); + for (ExecutableElement executableElement : methods) { + TypeMirror returnType = executableElement.getReturnType(); + boolean warning = false; + if ( returnType.getKind() == TypeKind.ARRAY ){ + warning = true; + } + else if ( returnType.getKind() == TypeKind.DECLARED){ + Element returnElement = result.getInfo().getTypes().asElement( + returnType ); + warning = returnElement.getKind() == ElementKind.ANNOTATION_TYPE; + } + if ( !warning ){ + continue; + } + if (AnnotationUtil.hasAnnotation(executableElement, + AnnotationUtil.NON_BINDING, result.getInfo()) ) + { + continue; + } + result.addNotification(Severity.WARNING, element, localizedWarning); + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/InterceptorBindingVerifier.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/InterceptorBindingVerifier.java new file mode 100644 index 000000000000..3cd27b778d6d --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/InterceptorBindingVerifier.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation; + +import java.lang.annotation.ElementType; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; + + +/** + * @author ads + * + */ +public class InterceptorBindingVerifier implements TargetVerifier { + + private InterceptorBindingVerifier(){ + } + + private static final InterceptorBindingVerifier INSTANCE = + new InterceptorBindingVerifier(); + + public static InterceptorBindingVerifier getInstance(){ + return INSTANCE; + } + + @Override + public boolean hasReqiredTarget( AnnotationMirror target , Set + targetTypes ) + { + int sz = 1; + if(targetTypes.size()>0){ + sz = targetTypes.size(); + if(targetTypes.contains( ElementType.TYPE)){ + sz--; + } + if ( targetTypes.contains( ElementType.METHOD)) { + sz--; + } + if (targetTypes.contains( ElementType.CONSTRUCTOR) ) + { + sz--; + } + } + return sz==0; + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/QualifierAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/QualifierAnalyzer.java new file mode 100644 index 000000000000..169c61e35cee --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/QualifierAnalyzer.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; + +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationElementAnalyzer.AnnotationAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.openide.util.NbBundle; +import org.netbeans.spi.editor.hints.Severity; + + +/** + * @author ads + * + */ +public class QualifierAnalyzer extends InterceptorBindingMembersAnalyzer { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationElementAnalyzer.AnnotationAnalyzer#analyze(javax.lang.model.element.TypeElement, java.util.concurrent.atomic.AtomicBoolean, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer.Result) + */ + @Override + public void analyze( TypeElement element, AtomicBoolean cancel, + CdiAnalysisResult result ) + { + if ( AnnotationUtil.hasAnnotation(element, AnnotationUtil.QUALIFIER_FQN, + result.getInfo())) + { + result.requireCdiEnabled(element); + QualifierTargetAnalyzer analyzer = new QualifierTargetAnalyzer(element, + result ); + if ( !analyzer.hasRuntimeRetention() ){ + result.addError( element, + NbBundle.getMessage(QualifierTargetAnalyzer.class, + INCORRECT_RUNTIME)); + } + if ( !analyzer.hasTarget()){ + result.addError( element, + NbBundle.getMessage(QualifierTargetAnalyzer.class, + "ERR_IncorrectQualifierTarget")); // NOI18N + } + if ( cancel.get() ){ + return; + } + checkMembers( element, result , NbBundle.getMessage( + QualifierAnalyzer.class, + "WARN_ArrayAnnotationValuedQualifierMember")); // NOI18N + } + } + + private static class QualifierTargetAnalyzer extends CdiAnnotationAnalyzer{ + + QualifierTargetAnalyzer( TypeElement element, CdiAnalysisResult result) + { + super(element, result); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.annotation.CdiAnnotationAnalyzer#getCdiMetaAnnotation() + */ + @Override + protected String getCdiMetaAnnotation() { + return AnnotationUtil.QUALIFIER; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.annotation.TargetAnalyzer#getTargetVerifier() + */ + @Override + protected TargetVerifier getTargetVerifier() { + return QualifierVerifier.getInstance( true ); + } + + } +} \ No newline at end of file diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/QualifierVerifier.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/QualifierVerifier.java new file mode 100644 index 000000000000..459977029d48 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/QualifierVerifier.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation; + +import java.lang.annotation.ElementType; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; + + +/** + * @author ads + * + */ +public class QualifierVerifier implements TargetVerifier { + + + private static final QualifierVerifier INSTANCE = new QualifierVerifier( false ); + + private static final QualifierVerifier EVENT_INSTANCE = + new QualifierVerifier( true ); + + private QualifierVerifier(boolean event){ + isEvent = event; + } + + public static QualifierVerifier getInstance( boolean event ){ + if ( event ){ + return EVENT_INSTANCE; + } + else { + return INSTANCE; + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.TargetVerifier#hasReqiredTarget(javax.lang.model.element.AnnotationMirror, java.util.Set) + */ + @Override + public boolean hasReqiredTarget( AnnotationMirror target, + Set targetTypes ) + { + boolean hasRequiredTarget = false; +// if ( isEvent() ){ TODO: any reason why it was different, ins specification event qualifier is just the same as usual, and example have 4 targets but it's just example? see #225556 + //especially it was updated for evvents before but specification is new for all qualifiers. keep for now commented + boolean hasFieldParameterTarget = targetTypes.contains( + ElementType.FIELD) && + targetTypes.contains(ElementType.PARAMETER); + if ( !hasFieldParameterTarget){ + hasRequiredTarget = (targetTypes.size() == 1 && + (targetTypes.contains(ElementType.TYPE) || + targetTypes.contains(ElementType.METHOD) || + targetTypes.contains(ElementType.FIELD))) || + (targetTypes.size() == 2 && + targetTypes.contains(ElementType.METHOD) && + targetTypes.contains(ElementType.FIELD));//see #244059 + } + else { + if ( targetTypes.size() == 2 ){ + hasRequiredTarget = true; + } + else { + hasRequiredTarget = + (targetTypes.size() == 4 && + targetTypes.contains( ElementType.METHOD) && + targetTypes.contains( ElementType.TYPE)) || + (targetTypes.size() == 3 && + targetTypes.contains( ElementType.METHOD)); + } + } +// } +// else { +// hasRequiredTarget = targetTypes.size() == 4 && +// targetTypes.contains( ElementType.METHOD) && +// targetTypes.contains(ElementType.FIELD) && +// targetTypes.contains(ElementType.PARAMETER)&& +// targetTypes.contains( ElementType.TYPE); +// } + + return hasRequiredTarget; + } + + private boolean isEvent(){ + return isEvent; + } + + private boolean isEvent; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/RuntimeRetentionAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/RuntimeRetentionAnalyzer.java new file mode 100644 index 000000000000..8d297fab7f65 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/RuntimeRetentionAnalyzer.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Map; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; + +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationHelper; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.parser.AnnotationParser; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; + + +/** + * @author ads + * + */ +public abstract class RuntimeRetentionAnalyzer { + + public void init( Element element, AnnotationHelper helper ) { + myHelper = helper; + myElement = element; + } + + public void init( Element element, CompilationInfo info ) { + init( element , new AnnotationHelper(info)); + } + + public boolean hasRuntimeRetention() { + Map types = getHelper() + .getAnnotationsByType(getElement().getAnnotationMirrors()); + AnnotationMirror retention = types.get(Retention.class.getCanonicalName()); + if ( retention == null ) { + handleNoRetention(); + return false; + } + + AnnotationParser parser = AnnotationParser.create(getHelper()); + parser.expectEnumConstant(AnnotationUtil.VALUE, getHelper().resolveType( + RetentionPolicy.class.getCanonicalName()), null); + + String retentionPolicy = parser.parse(retention).get(AnnotationUtil.VALUE, + String.class); + return RetentionPolicy.RUNTIME.toString().equals(retentionPolicy); + } + + protected abstract void handleNoRetention(); + + protected Element getElement(){ + return myElement; + } + + protected AnnotationHelper getHelper(){ + return myHelper; + } + + private AnnotationHelper myHelper; + private Element myElement; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/ScopeAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/ScopeAnalyzer.java new file mode 100644 index 000000000000..616fc5f8d7ce --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/ScopeAnalyzer.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation; + +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.TypeElement; + +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationElementAnalyzer.AnnotationAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class ScopeAnalyzer implements AnnotationAnalyzer { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationElementAnalyzer.AnnotationAnalyzer#analyze(javax.lang.model.element.TypeElement, java.util.concurrent.atomic.AtomicBoolean, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer.Result) + */ + @Override + public void analyze( TypeElement element, AtomicBoolean cancel, + CdiAnalysisResult result) + { + CompilationInfo compInfo = result.getInfo(); + boolean isScope = AnnotationUtil.hasAnnotation(element, + AnnotationUtil.SCOPE_FQN , compInfo); + boolean isNormalScope = AnnotationUtil.hasAnnotation(element, + AnnotationUtil.NORMAL_SCOPE_FQN, compInfo); + if ( isScope || isNormalScope ){ + result.requireCdiEnabled(element); + ScopeTargetAnalyzer analyzer = new ScopeTargetAnalyzer(element, + result, isNormalScope); + if ( cancel.get() ){ + return; + } + if ( !analyzer.hasRuntimeRetention() ){ + result.addError( element, + NbBundle.getMessage(ScopeAnalyzer.class, + INCORRECT_RUNTIME)); + } + if ( cancel.get() ){ + return; + } + if ( !analyzer.hasTarget()){ + result.addError( element, + NbBundle.getMessage(ScopeAnalyzer.class, + "ERR_IncorrectScopeTarget")); // NOI18N + } + } + } + + private static class ScopeTargetAnalyzer extends CdiAnnotationAnalyzer { + + ScopeTargetAnalyzer(TypeElement element, CdiAnalysisResult result, + boolean normalScope ) + { + super( element , result ); + isNormalScope = normalScope; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.annotation.TargetAnalyzer#getTargetVerifier() + */ + @Override + protected TargetVerifier getTargetVerifier() { + return ScopeVerifier.getInstance(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.annotation.CdiAnnotationAnalyzer#getCdiMetaAnnotation() + */ + @Override + protected String getCdiMetaAnnotation() { + if ( isNormalScope ){ + return AnnotationUtil.NORMAL_SCOPE; + } + else { + return AnnotationUtil.SCOPE; + } + } + + private boolean isNormalScope; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/ScopeVerifier.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/ScopeVerifier.java new file mode 100644 index 000000000000..a816832c5906 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/ScopeVerifier.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation; + +import java.lang.annotation.ElementType; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; + + +/** + * @author ads + * + */ +public class ScopeVerifier implements TargetVerifier { + + private static final ScopeVerifier INSTANCE = new ScopeVerifier(); + + private ScopeVerifier( ){ + } + + public static ScopeVerifier getInstance(){ + return INSTANCE; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.TargetVerifier#hasReqiredTarget(javax.lang.model.element.AnnotationMirror, java.util.Set) + */ + @Override + public boolean hasReqiredTarget( AnnotationMirror target, + Set targetTypes ) + { + boolean hasRequiredTarget = targetTypes.contains( + ElementType.METHOD) && + targetTypes.contains(ElementType.FIELD) && + targetTypes.contains( ElementType.TYPE); + return hasRequiredTarget; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/StereotypeAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/StereotypeAnalyzer.java new file mode 100644 index 000000000000..7135d923c833 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/StereotypeAnalyzer.java @@ -0,0 +1,262 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation; + +import java.lang.annotation.ElementType; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationHelper; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractScopedAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationModelAnalyzer.AnnotationAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.impl.model.WebBeansModelProviderImpl; +import org.openide.util.NbBundle; +import org.netbeans.spi.editor.hints.Severity; + + +/** + * @author ads + * + */ +public class StereotypeAnalyzer extends AbstractScopedAnalyzer implements AnnotationAnalyzer { + + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationModelAnalyzer.AnnotationAnalyzer#analyze(javax.lang.model.element.TypeElement, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.util.List, org.netbeans.api.java.source.CompilationInfo, java.util.concurrent.atomic.AtomicBoolean) + */ + @Override + public void analyze( TypeElement element, WebBeansModel model , + AtomicBoolean cancel , + Result result) + { + boolean isStereotype = AnnotationUtil.hasAnnotation(element, + AnnotationUtil.STEREOTYPE_FQN, model.getCompilationController()); + if ( !isStereotype ){ + return; + } + result.requireCdiEnabled(element, model); + if ( cancel.get() ){ + return; + } + analyzeScope((Element)element, model, cancel, result ); + if (cancel.get() ){ + return; + } + checkName( element, model, result ); + if ( cancel.get() ){ + return; + } + Set targets = checkDefinition( element , model, result ); + if ( cancel.get() ){ + return; + } + checkInterceptorBindings( element , targets, model , result ); + if ( cancel.get() ){ + return; + } + checkTransitiveStereotypes( element , targets, model , result ); + if ( cancel.get() ){ + return; + } + checkTyped( element , model , result ); + if ( cancel.get() ){ + return; + } + checkQualifers( element , model, result ); + } + + private void checkQualifers( TypeElement element, WebBeansModel model, + Result result ) + { + List qualifiers = model.getQualifiers(element, true); + for (AnnotationMirror annotationMirror : qualifiers) { + Element annotation = annotationMirror.getAnnotationType().asElement(); + if ( annotation instanceof TypeElement && + ((TypeElement)annotation).getQualifiedName().contentEquals( + AnnotationUtil.NAMED)) + { + continue; + } + else { + result.addNotification( Severity.WARNING , element, model, + NbBundle.getMessage(StereotypeAnalyzer.class, + "WARN_QualifiedStereotype")); // NOI18N + break; + } + } + } + + private void checkTyped( TypeElement element, WebBeansModel model, + Result result ) + { + AnnotationMirror typed = AnnotationUtil.getAnnotationMirror(element, + model.getCompilationController(), AnnotationUtil.TYPED); + if ( typed != null ){ + result.addNotification( Severity.WARNING , element, model, + NbBundle.getMessage(StereotypeAnalyzer.class, + "WARN_TypedStereotype")); // NOI18N + } + } + + private void checkTransitiveStereotypes( TypeElement element, + final Set targets, WebBeansModel model, + Result result ) + { + AnnotationHelper helper = new AnnotationHelper( + model.getCompilationController()); + List stereotypes = WebBeansModelProviderImpl + .getAllStereotypes(element, helper); + for (AnnotationMirror stereotypeAnnotation : stereotypes) { + Element annotationElement = stereotypeAnnotation + .getAnnotationType().asElement(); + if (annotationElement instanceof TypeElement) { + TypeElement stereotype = (TypeElement) annotationElement; + Set declaredTargetTypes = TargetAnalyzer + .getDeclaredTargetTypes(helper, stereotype); + if (declaredTargetTypes != null + && declaredTargetTypes.size() == 1 + && declaredTargetTypes.contains(ElementType.TYPE)) + { + if (targets.size() == 1 + && targets.contains(ElementType.TYPE)) + { + continue; + } + else { + String fqn = stereotype.getQualifiedName().toString(); + result.addError(element, model, + NbBundle.getMessage( + StereotypeAnalyzer.class, + "ERR_IncorrectTransitiveTarget", // NOI18N + fqn)); + } + } + } + } + } + + private void checkInterceptorBindings( TypeElement element, + Set targets, WebBeansModel model, + Result result ) + { + if (targets == null) { + return; + } + if (targets.size() == 1 && targets.contains(ElementType.TYPE)) { + return; + } + int interceptorsCount = model.getInterceptorBindings(element).size(); + if (interceptorsCount != 0) { + result.addError(element,model, + NbBundle.getMessage(StereotypeAnalyzer.class, + "ERR_IncorrectTargetWithInterceptorBindings")); // NOI18N + } + } + + private Set checkDefinition( TypeElement element, + WebBeansModel model , Result result ) + { + StereotypeTargetAnalyzer analyzer = new StereotypeTargetAnalyzer(element, + model, result ); + if ( !analyzer.hasRuntimeRetention()){ + result.addError( element, model, + NbBundle.getMessage(StereotypeAnalyzer.class, + INCORRECT_RUNTIME)); + } + if ( !analyzer.hasTarget()){ + result.addError( element, model, + NbBundle.getMessage(StereotypeAnalyzer.class, + "ERR_IncorrectStereotypeTarget")); // NOI18N + return null; + } + else { + return analyzer.getDeclaredTargetTypes(); + } + } + + private void checkName( TypeElement element, WebBeansModel model, + Result result ) + { + AnnotationMirror named = AnnotationUtil.getAnnotationMirror(element, + AnnotationUtil.NAMED , model.getCompilationController()); + if ( named == null ){ + return; + } + Map members = + named.getElementValues(); + for (Entry entry: + members.entrySet()) + { + ExecutableElement member = entry.getKey(); + if ( member.getSimpleName().contentEquals(AnnotationUtil.VALUE)){ + result.addError( element, model, + NbBundle.getMessage(StereotypeAnalyzer.class, + "ERR_NonEmptyNamedStereotype")); // NOI18N + } + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractScopedAnalyzer#checkScope(javax.lang.model.element.TypeElement, javax.lang.model.element.Element, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.util.concurrent.atomic.AtomicBoolean, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result) + */ + @Override + protected void checkScope( TypeElement scopeElement, Element element, + WebBeansModel model, AtomicBoolean cancel , Result result ) + { + } + + private static class StereotypeTargetAnalyzer extends CdiAnnotationAnalyzer{ + + StereotypeTargetAnalyzer( TypeElement element, WebBeansModel model, + Result result ) + { + super(element, model, result ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.annotation.CdiAnnotationAnalyzer#getCdiMetaAnnotation() + */ + @Override + protected String getCdiMetaAnnotation() { + return AnnotationUtil.STEREOTYPE; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.annotation.TargetAnalyzer#getTargetVerifier() + */ + @Override + protected TargetVerifier getTargetVerifier() { + return StereotypeVerifier.getInstance(); + } + + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/StereotypeVerifier.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/StereotypeVerifier.java new file mode 100644 index 000000000000..f017ff6d47cb --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/StereotypeVerifier.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation; + +import java.lang.annotation.ElementType; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; + + +/** + * @author ads + * + */ +public class StereotypeVerifier implements TargetVerifier { + + private static final StereotypeVerifier INSTANCE = new StereotypeVerifier(); + + private StereotypeVerifier(){ + } + + public static StereotypeVerifier getInstance(){ + return INSTANCE; + } + + @Override + public boolean hasReqiredTarget( AnnotationMirror target, + Set targetTypes ) + { + boolean hasRequiredTarget = false; + if ( targetTypes.contains( ElementType.METHOD) && + targetTypes.contains(ElementType.FIELD) && + targetTypes.contains( ElementType.TYPE) + && targetTypes.size() == 3) + { + hasRequiredTarget = true; + } + else if ( targetTypes.size() == 2 && + targetTypes.contains( ElementType.METHOD) && + targetTypes.contains(ElementType.FIELD)) + { + hasRequiredTarget = true; + } + else if ( targetTypes.size() == 1 ){ + hasRequiredTarget = targetTypes.contains( ElementType.METHOD) || + targetTypes.contains( ElementType.FIELD) || + targetTypes.contains( ElementType.TYPE); + } + return hasRequiredTarget; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/TargetAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/TargetAnalyzer.java new file mode 100644 index 000000000000..91add8f98891 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/TargetAnalyzer.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationHelper; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.parser.AnnotationParser; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.parser.ArrayValueHandler; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; + + +/** + * @author ads + * + */ +public abstract class TargetAnalyzer extends RuntimeRetentionAnalyzer + implements TargetVerifier +{ + + public boolean hasTarget() { + Map types = getHelper() + .getAnnotationsByType(getElement().getAnnotationMirrors()); + AnnotationMirror target = types.get(Target.class.getCanonicalName()); + if (target == null) { + handleNoTarget(); + } + return hasReqiredTarget( target , getDeclaredTargetTypes( getHelper(), + target )); + } + + public Set getDeclaredTargetTypes() { + Map types = getHelper() + .getAnnotationsByType(getElement().getAnnotationMirrors()); + AnnotationMirror target = types.get(Target.class.getCanonicalName()); + if (target == null) { + return Collections.emptySet(); + } + return getDeclaredTargetTypes( getHelper(), target ); + } + + public static Set getDeclaredTargetTypes( + AnnotationHelper helper, TypeElement element ) + { + Map types = helper + .getAnnotationsByType(element.getAnnotationMirrors()); + AnnotationMirror target = types.get(Target.class.getCanonicalName()); + if (target == null) { + return Collections.emptySet(); + } + return getDeclaredTargetTypes( helper, target ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.TargetVerifier#hasReqiredTarget(javax.lang.model.element.AnnotationMirror, java.util.Set) + */ + @Override + public boolean hasReqiredTarget( AnnotationMirror target, + Set set ) + { + return getTargetVerifier().hasReqiredTarget(target, set ); + } + + protected abstract TargetVerifier getTargetVerifier(); + + protected abstract void handleNoTarget(); + + private static Set getDeclaredTargetTypes( + AnnotationHelper helper, AnnotationMirror target) + { + AnnotationParser parser = AnnotationParser.create(helper); + final Set elementTypes = new HashSet(); + parser.expectEnumConstantArray( AnnotationUtil.VALUE, + helper.resolveType( + ElementType.class.getCanonicalName()), + new ArrayValueHandler() { + + @Override + public Object handleArray( List arrayMembers ) { + for (AnnotationValue arrayMember : arrayMembers) { + String value = arrayMember.getValue().toString(); + elementTypes.add(value); + } + return null; + } + } , null); + + parser.parse( target ); + Set result = new HashSet(); + for (String type : elementTypes) { + ElementType elementType = ElementType.valueOf(ElementType.class, type); + result.add( elementType ); + } + return result; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/TargetVerifier.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/TargetVerifier.java new file mode 100644 index 000000000000..00ad26e90fd1 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/annotation/TargetVerifier.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation; + +import java.lang.annotation.ElementType; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; + + +/** + * @author ads + * + */ +public interface TargetVerifier { + + boolean hasReqiredTarget(AnnotationMirror target, Set targetTypes); + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/field/Bundle.properties b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/field/Bundle.properties new file mode 100644 index 000000000000..60bbef26f1e8 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/field/Bundle.properties @@ -0,0 +1,48 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +ERR_BadRestritedFieldType=Field\'s bean class specifies @Typed annotation, \ +and the value member specifies a class which does not correspond to a type in \ +the unrestricted set of bean types of a bean. +ERR_DelegateHasNoInject=Field is declared as @Delegate but it is not an injection point. +ERR_DelegateIsNotInDecorator=Field is declared as @Delegate but its enclosing \ +type element is not a decorator. +ERR_NonStaticProducerSessionBean=A producer field must be a static field of the \ +session bean class. + +ERR_ProducerHasTypeVar=A producer field type should not be a type variable. +ERR_ProducerHasWildcard=A producer field type should not contain a wildcard type parameter. + +ERR_WrongScopeParameterizedProducer=The producer field has parameterized type \ +with a type variable and has scope {0} (should be @Dependent). + +ERR_WrongQualifierInjectionPointMeta=An injection point has type InjectionPoint \ +and qualifier @Default but bean declares not @Dependent scope. + +ERR_DelegateTypeHasNoDecoratedType=The delegate type of a decorator must implement \ +or extend every decorated type of decorator. + +ERR_FinalDecoratedBean=Delegate injection point matches a managed bean {0} \ +which class is declared final. + +ERR_FinalMethodDecoratedBean=Delegate injection point matches a managed bean {0} \ +with final method {1} which is implemented by decorator. + +WARN_NamedInjectionPoint=The use of @Named as an injection point qualifier is not recommended. + +ERR_NotPassivationProducer=Producer field has a passivating scope {0} and should be \ +passivation capable. But its type is declared final and does not implement Serializable. \ No newline at end of file diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/field/DelegateFieldAnalizer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/field/DelegateFieldAnalizer.java new file mode 100644 index 000000000000..a3169a7de804 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/field/DelegateFieldAnalizer.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.field; + +import java.io.Serializable; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.FieldElementAnalyzer.FieldAnalyzer; +import org.netbeans.modules.jakarta.web.beans.hints.EditorAnnotationsHelper; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class DelegateFieldAnalizer implements FieldAnalyzer { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.FieldElementAnalyzer.FieldAnalyzer#analyze(javax.lang.model.element.VariableElement, javax.lang.model.type.TypeMirror, javax.lang.model.element.TypeElement, org.netbeans.api.java.source.CompilationInfo, java.util.List, java.util.concurrent.atomic.AtomicBoolean) + */ + @Override + public void analyze( VariableElement element, TypeMirror elementType, + TypeElement parent, AtomicBoolean cancel, + CdiAnalysisResult result ) + { + CompilationInfo compInfo = result.getInfo(); + if (!AnnotationUtil.hasAnnotation(element, AnnotationUtil.DELEGATE_FQN, + compInfo)) + { + return; + } + result.requireCdiEnabled(element); + if (!AnnotationUtil.hasAnnotation(element, AnnotationUtil.INJECT_FQN, + compInfo)) + { + result.addError(element, NbBundle.getMessage( + DelegateFieldAnalizer.class, + "ERR_DelegateHasNoInject")); // NOI18N + } + Element clazz = element.getEnclosingElement(); + if (!AnnotationUtil.hasAnnotation(clazz, AnnotationUtil.DECORATOR, + compInfo)) + { + result.addError(element, NbBundle.getMessage( + DelegateFieldAnalizer.class, + "ERR_DelegateIsNotInDecorator")); // NOI18N + } + EditorAnnotationsHelper helper = EditorAnnotationsHelper.getInstance( + result); + if ( helper != null ){ + helper.addDelegate(result, element ); + } + if ( cancel.get()){ + return; + } + checkDelegateType(element, elementType, parent, result ); + } + + private void checkDelegateType( VariableElement element, + TypeMirror elementType, TypeElement parent, + CdiAnalysisResult result ) + { + Collection decoratedTypes = getDecoratedTypes( parent , + result.getInfo() ); + for (TypeMirror decoratedType : decoratedTypes) { + if ( !result.getInfo().getTypes().isSubtype( elementType,decoratedType )){ + result.addError(element, NbBundle.getMessage( + DelegateFieldAnalizer.class, + "ERR_DelegateTypeHasNoDecoratedType")); // NOI18N + return; + } + } + } + + public static Collection getDecoratedTypes( TypeElement element , + CompilationInfo info ) + { + TypeElement serializable = info.getElements().getTypeElement( + Serializable.class.getCanonicalName()); + Collection result = new LinkedList(); + collectDecoratedTypes( element.asType() , result , serializable, info ); + return result; + } + + private static void collectDecoratedTypes( TypeMirror type, + Collection result, TypeElement serializable, + CompilationInfo info) + { + List directSupertypes = info.getTypes(). + directSupertypes(type); + for (TypeMirror superType : directSupertypes) { + Element element = info.getTypes().asElement(superType); + if( element == null || element.equals( serializable) ) + { + continue; + } + if ( element.getKind() == ElementKind.INTERFACE ){ + result.add( superType ); + } + collectDecoratedTypes(superType, result, serializable, info); + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/field/InjectionPointAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/field/InjectionPointAnalyzer.java new file mode 100644 index 000000000000..bb3a48bde1d9 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/field/InjectionPointAnalyzer.java @@ -0,0 +1,226 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.field; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import javax.swing.text.Document; + +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationHelper; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractDecoratorAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.FieldModelAnalyzer.FieldAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result; +import org.netbeans.modules.jakarta.web.beans.api.model.CdiException; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult.ResultKind; +import org.netbeans.modules.jakarta.web.beans.api.model.InjectionPointDefinitionError; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.hints.EditorAnnotationsHelper; +import org.netbeans.spi.editor.hints.Severity; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class InjectionPointAnalyzer extends AbstractDecoratorAnalyzer implements FieldAnalyzer { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.FieldModelAnalyzer.FieldAnalyzer#analyze(javax.lang.model.element.VariableElement, javax.lang.model.type.TypeMirror, javax.lang.model.element.TypeElement, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.util.List, org.netbeans.api.java.source.CompilationInfo, java.util.concurrent.atomic.AtomicBoolean) + */ + @Override + public void analyze( final VariableElement element, TypeMirror elementType, + TypeElement parent, WebBeansModel model, + AtomicBoolean cancel , + Result result ) + { + try { + if (model.isInjectionPoint(element) ){ + boolean isDelegate = false; + result.requireCdiEnabled(element, model); + checkInjectionPointMetadata( element, elementType , parent, model , + cancel , result ); + checkNamed( element, model , cancel, result); + if ( cancel.get() ){ + return; + } + if ( !model.isDynamicInjectionPoint(element)) { + isDelegate = AnnotationUtil.isDelegate(element, parent, model); + if (!checkBuiltInBeans(element, elementType, model, cancel)) + { + DependencyInjectionResult res = model + .lookupInjectables(element, null, cancel); + checkResult(res, element, model, result); + if (isDelegate) { + analyzeDecoratedBeans(res, element, null, parent, + model, result); + } + } + } + boolean isEvent = model.isEventInjectionPoint(element); + if ( isEvent ){ + ElementHandle modelHandle = ElementHandle.create(element); + EditorAnnotationsHelper helper = EditorAnnotationsHelper.getInstance( + result); + if ( helper != null ){ + helper.addEventInjectionPoint( result, + modelHandle.resolve(result.getInfo())); + } + } + else if ( isDelegate || AnnotationUtil.hasAnnotation(element, + AnnotationUtil.DELEGATE_FQN, model.getCompilationController())) + { + return; + } + else { + ElementHandle modelHandle = ElementHandle.create(element); + EditorAnnotationsHelper helper = EditorAnnotationsHelper.getInstance( + result); + if (helper != null ){ + helper.addInjectionPoint( result, + modelHandle.resolve(result.getInfo())); + } + } + } + } + catch (InjectionPointDefinitionError e) { + result.requireCdiEnabled(element, model); + informInjectionPointDefError(e, element, model, result ); + } + } + + private void checkNamed( VariableElement element, WebBeansModel model, + AtomicBoolean cancel, Result result ) + { + if( cancel.get() ){ + return; + } + if ( AnnotationUtil.hasAnnotation(element, AnnotationUtil.NAMED, + model.getCompilationController()) ) + { + result.addNotification( Severity.WARNING , element, model, + NbBundle.getMessage(InjectionPointAnalyzer.class, + "WARN_NamedInjectionPoint")); // NOI18N + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractDecoratorAnalyzer#addClassError(javax.lang.model.element.VariableElement, java.lang.Object, javax.lang.model.element.TypeElement, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result) + */ + @Override + protected void addClassError( VariableElement element, Void fake, + TypeElement decoratedBean, WebBeansModel model, Result result ) + { + result.addError( element , model, + NbBundle.getMessage(InjectionPointAnalyzer.class, + "ERR_FinalDecoratedBean", // NOI18N + decoratedBean.getQualifiedName().toString())); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractDecoratorAnalyzer#addMethodError(javax.lang.model.element.VariableElement, java.lang.Object, javax.lang.model.element.TypeElement, javax.lang.model.element.Element, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result) + */ + @Override + protected void addMethodError( VariableElement element, Void fake, + TypeElement decoratedBean, Element decoratedMethod, + WebBeansModel model, Result result ) + { + result.addError( + element, model, NbBundle.getMessage( + InjectionPointAnalyzer.class, + "ERR_FinalMethodDecoratedBean", // NOI18N + decoratedBean.getQualifiedName().toString(), + decoratedMethod.getSimpleName().toString())); + } + + private void checkInjectionPointMetadata( VariableElement element, + TypeMirror elementType , TypeElement parent, WebBeansModel model, + AtomicBoolean cancel , Result result ) + { + TypeElement injectionPointType = model.getCompilationController(). + getElements().getTypeElement(AnnotationUtil.INJECTION_POINT); + if ( injectionPointType == null ){ + return; + } + Element varElement = model.getCompilationController().getTypes().asElement( + elementType ); + if ( !injectionPointType.equals(varElement)){ + return; + } + if ( cancel.get()){ + return; + } + List qualifiers = model.getQualifiers(element, true); + AnnotationHelper helper = new AnnotationHelper(model.getCompilationController()); + Map qualifiersFqns = helper. + getAnnotationsByType(qualifiers); + boolean hasDefault = model.hasImplicitDefaultQualifier( element ); + if ( !hasDefault && qualifiersFqns.keySet().contains(AnnotationUtil.DEFAULT_FQN)){ + hasDefault = true; + } + if ( !hasDefault || cancel.get() ){ + return; + } + try { + String scope = model.getScope( parent ); + if ( scope != null && !AnnotationUtil.DEPENDENT.equals( scope )){ + result.addError(element , model, + NbBundle.getMessage( + InjectionPointAnalyzer.class, "ERR_WrongQualifierInjectionPointMeta")); // NOI18N + } + } + catch (CdiException e) { + // this exception will be handled in the appropriate scope analyzer + return; + } + } + + private void checkResult( DependencyInjectionResult res , + VariableElement var, WebBeansModel model, + Result result ) + { + if ( res instanceof DependencyInjectionResult.Error ){ + ResultKind kind = res.getKind(); + Severity severity = Severity.WARNING; + if ( kind == DependencyInjectionResult.ResultKind.DEFINITION_ERROR){ + severity = Severity.ERROR; + } + String message = ((DependencyInjectionResult.Error)res).getMessage(); + result.addNotification(severity, var , model, message); + } + } + + private void informInjectionPointDefError(InjectionPointDefinitionError exception , + Element element, WebBeansModel model, + Result result ) + { + result.addError(element, model, exception.getMessage()); + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/field/ProducerFieldAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/field/ProducerFieldAnalyzer.java new file mode 100644 index 000000000000..f2d3cbcd328b --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/field/ProducerFieldAnalyzer.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.field; + +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractProducerAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.FieldElementAnalyzer.FieldAnalyzer; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class ProducerFieldAnalyzer extends AbstractProducerAnalyzer + implements FieldAnalyzer +{ + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.FieldElementAnalyzer.FieldAnalyzer#analyze(javax.lang.model.element.VariableElement, javax.lang.model.type.TypeMirror, javax.lang.model.element.TypeElement, org.netbeans.api.java.source.CompilationInfo, java.util.List, java.util.concurrent.atomic.AtomicBoolean) + */ + @Override + public void analyze( VariableElement element, TypeMirror elementType, + TypeElement parent, AtomicBoolean cancel, + CdiAnalysisResult result ) + { + CompilationInfo compInfo = result.getInfo(); + if ( !AnnotationUtil.hasAnnotation(element, AnnotationUtil.PRODUCES_FQN, + compInfo )) + { + return; + } + result.requireCdiEnabled(element); + if ( cancel.get() ){ + return; + } + checkSessionBean( element , parent , result ); + if ( cancel.get() ){ + return; + } + checkType( element, elementType, result ); + } + + @Override + protected void hasTypeVar( Element element, TypeMirror type, + CdiAnalysisResult result ) + { + result.addError( element, NbBundle.getMessage( + ProducerFieldAnalyzer.class, "ERR_ProducerHasTypeVar")); // NOI18N + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractProducerAnalyzer#hasWildCard(javax.lang.model.element.Element, javax.lang.model.type.TypeMirror, org.netbeans.api.java.source.CompilationInfo, java.util.List) + */ + @Override + protected void hasWildCard( Element element, TypeMirror type, + CdiAnalysisResult result ) + { + result.addError(element, NbBundle.getMessage( + ProducerFieldAnalyzer.class,"ERR_ProducerHasWildcard")); // NOI18N + } + + private void checkSessionBean( VariableElement element, TypeElement parent, + CdiAnalysisResult result ) + { + if ( !AnnotationUtil.isSessionBean( parent , result.getInfo())) { + return; + } + Set modifiers = element.getModifiers(); + if ( !modifiers.contains(Modifier.STATIC)){ + result.addError( element, NbBundle.getMessage( + ProducerFieldAnalyzer.class, + "ERR_NonStaticProducerSessionBean")); // NOI18N + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/field/ScopedFieldAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/field/ScopedFieldAnalyzer.java new file mode 100644 index 000000000000..e59eb61823e4 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/field/ScopedFieldAnalyzer.java @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.field; + +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractScopedAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.FieldModelAnalyzer.FieldAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class ScopedFieldAnalyzer extends AbstractScopedAnalyzer implements + FieldAnalyzer +{ + + @Override + public void analyze( VariableElement element, TypeMirror elementType, + TypeElement parent, WebBeansModel model, + AtomicBoolean cancel, Result result ) + { + if ( AnnotationUtil.hasAnnotation(element, AnnotationUtil.PRODUCES_FQN, + model.getCompilationController())) + { + result.requireCdiEnabled(element, model); + analyzeScope(element, model, cancel , result ); + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractScopedAnalyzer#checkScope(javax.lang.model.element.TypeElement, javax.lang.model.element.Element, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.util.concurrent.atomic.AtomicBoolean, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result) + */ + @Override + protected void checkScope( TypeElement scopeElement, Element element, + WebBeansModel model, AtomicBoolean cancel, Result result ) + { + if ( scopeElement.getQualifiedName().contentEquals( AnnotationUtil.DEPENDENT)){ + return; + } + if ( cancel.get() ){ + return; + } + if (hasTypeVarParameter(element.asType())) { + result.addError(element, model, + NbBundle.getMessage( + ScopedFieldAnalyzer.class, + "ERR_WrongScopeParameterizedProducer", // NOI18N + scopeElement.getQualifiedName().toString())); + } + if ( cancel.get() ){ + return; + } + checkPassivationCapable(scopeElement, element, model, result); + } + + private void checkPassivationCapable( TypeElement scopeElement, + Element element, WebBeansModel model, Result result ) + { + if ( !isPassivatingScope(scopeElement, model) ){ + return; + } + TypeMirror type = element.asType(); + if ( type.getKind().isPrimitive() ){ + return; + } + if ( isSerializable(type, model)){ + return; + } + Element typeElement = model.getCompilationController().getTypes(). + asElement( type ); + if ( typeElement == null ){ + return; + } + if ( typeElement.getModifiers().contains( Modifier.FINAL )){ + result.addError( element, model, + NbBundle.getMessage(ScopedFieldAnalyzer.class, + "ERR_NotPassivationProducer", // NOI18N + scopeElement.getQualifiedName().toString())); + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/field/TypedFieldAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/field/TypedFieldAnalyzer.java new file mode 100644 index 000000000000..4a1f3d802565 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/field/TypedFieldAnalyzer.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.field; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractTypedAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.FieldElementAnalyzer.FieldAnalyzer; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class TypedFieldAnalyzer extends AbstractTypedAnalyzer implements FieldAnalyzer { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.FieldElementAnalyzer.FieldAnalyzer#analyze(javax.lang.model.element.VariableElement, javax.lang.model.type.TypeMirror, javax.lang.model.element.TypeElement, java.util.concurrent.atomic.AtomicBoolean, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer.Result) + */ + @Override + public void analyze( VariableElement element, TypeMirror elementType, + TypeElement parent, AtomicBoolean cancel, + CdiAnalysisResult result ) + { + analyze(element, elementType, cancel , result ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractTypedAnalyzer#addError(javax.lang.model.element.Element, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer.Result) + */ + @Override + protected void addError( Element element, CdiAnalysisResult result ) + { + result.addError( element, NbBundle.getMessage( + TypedFieldAnalyzer.class, "ERR_BadRestritedFieldType")); // NOI18N + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractTypedAnalyzer#checkSpecializes(javax.lang.model.element.Element, javax.lang.model.type.TypeMirror, java.util.List, java.util.concurrent.atomic.AtomicBoolean, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer.Result) + */ + @Override + protected void checkSpecializes( Element element, TypeMirror elementType, + List restrictedTypes, AtomicBoolean cancel , CdiAnalysisResult result) + { + // production fields cannot be specialized + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/AnnotationsAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/AnnotationsAnalyzer.java new file mode 100644 index 000000000000..d5ad97284c66 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/AnnotationsAnalyzer.java @@ -0,0 +1,242 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.method; + +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; + +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.MethodElementAnalyzer.MethodAnalyzer; +import org.netbeans.modules.jakarta.web.beans.hints.EditorAnnotationsHelper; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class AnnotationsAnalyzer implements MethodAnalyzer { + + private static final String EJB = "ejb"; // NOI18N + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.MethodElementAnalyzer.MethodAnalyzer#analyze(javax.lang.model.element.ExecutableElement, javax.lang.model.type.TypeMirror, javax.lang.model.element.TypeElement, java.util.concurrent.atomic.AtomicBoolean, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer.Result) + */ + @Override + public void analyze( ExecutableElement element, TypeMirror returnType, + TypeElement parent, AtomicBoolean cancel , CdiAnalysisResult result ) + { + checkProductionObserverDisposerInject( element , parent , + cancel , result ); + if ( cancel.get()){ + return; + } + } + + private void checkProductionObserverDisposerInject( + ExecutableElement element, TypeElement parent, AtomicBoolean cancel , + CdiAnalysisResult result ) + { + CompilationInfo compInfo = result.getInfo(); + boolean isProducer = AnnotationUtil.hasAnnotation(element, + AnnotationUtil.PRODUCES_FQN, compInfo); + boolean isInitializer = AnnotationUtil.hasAnnotation(element, + AnnotationUtil.INJECT_FQN, compInfo); + int observesCount = 0; + int disposesCount = 0; + List parameters = element.getParameters(); + for (VariableElement param : parameters) { + if ( cancel.get() ){ + return; + } + if ( AnnotationUtil.hasAnnotation( param, AnnotationUtil.OBSERVES_FQN, + compInfo)) + { + observesCount++; + } + if ( AnnotationUtil.hasAnnotation( param, AnnotationUtil.DISPOSES_FQN, + compInfo)) + { + disposesCount++; + } + } + if ( observesCount >0 ){ + EditorAnnotationsHelper helper = EditorAnnotationsHelper.getInstance(result); + if ( helper != null ){ + helper.addObserver( result , element ); + } + } + String firstAnnotation = null; + String secondAnnotation = null; + if ( isProducer ){ + firstAnnotation = AnnotationUtil.PRODUCES; + if ( isInitializer ){ + secondAnnotation = AnnotationUtil.INJECT; + } + else if ( observesCount >0 ){ + secondAnnotation = AnnotationUtil.OBSERVES; + } + else if ( disposesCount >0 ){ + secondAnnotation = AnnotationUtil.DISPOSES; + } + } + else if ( isInitializer ){ + firstAnnotation = AnnotationUtil.INJECT; + if ( observesCount >0 ){ + secondAnnotation = AnnotationUtil.OBSERVES; + } + else if ( disposesCount >0 ){ + secondAnnotation = AnnotationUtil.DISPOSES; + } + } + else if ( observesCount >0 ){ + firstAnnotation = AnnotationUtil.OBSERVES; + if ( disposesCount >0 ){ + secondAnnotation = AnnotationUtil.DISPOSES; + } + } + if ( firstAnnotation != null && secondAnnotation != null ){ + result.addError( element, NbBundle.getMessage( + AnnotationsAnalyzer.class, "ERR_BothAnnotationsMethod", // NOI18N + firstAnnotation, secondAnnotation )); + } + + // Test quantity of observer parameters + if ( observesCount > 1){ + result.addError( element, NbBundle.getMessage( + AnnotationsAnalyzer.class, "ERR_ManyObservesParameter" )); // NOI18N + } + // Test quantity of disposes parameters + else if ( disposesCount >1 ){ + result.addError( element, NbBundle.getMessage( + AnnotationsAnalyzer.class, "ERR_ManyDisposesParameter")); // NOI18N + } + + // A producer/disposer method must be a non-abstract method . + checkAbstractMethod(element, result, isProducer, + disposesCount>0); + + checkBusinessMethod( element , result, isProducer, + disposesCount >0 , observesCount > 0); + + if ( isInitializer ){ + checkInitializerMethod(element, parent , result ); + } + } + + /** + * A producer/disposer/observer non-static method of a session bean class + * should be a business method of the session bean. + */ + private void checkBusinessMethod( ExecutableElement element, + CdiAnalysisResult result ,boolean isProducer, boolean isDisposer, boolean isObserver ) + { + CompilationInfo compInfo = result.getInfo(); + if ( !isProducer && !isDisposer && !isObserver ){ + return; + } + Set modifiers = element.getModifiers(); + if ( modifiers.contains(Modifier.STATIC) ){ + return; + } + TypeElement containingClass = compInfo.getElementUtilities(). + enclosingTypeElement(element); + if ( !AnnotationUtil.isSessionBean( containingClass, compInfo) ){ + return; + } + String methodName = element.getSimpleName().toString(); + boolean isBusinessMethod = true; + if ( methodName.startsWith(EJB)){ + isBusinessMethod = false; + } + if (AnnotationUtil.isLifecycleCallback(element, compInfo)){ + isBusinessMethod = false; + } + if ( modifiers.contains(Modifier.FINAL) || + !modifiers.contains( Modifier.PUBLIC) ) + { + isBusinessMethod = false; + } + if ( !isBusinessMethod ){ + String key = null; + if ( isProducer ){ + key = "ERR_ProducerNotBusiness"; // NOI18N + } + else if ( isDisposer ){ + key = "ERR_DisposerNotBusiness"; // NOI18N + } + else if ( isObserver ){ + key = "ERR_ObserverNotBusiness"; // NOI18N + } + result.addError( element, NbBundle.getMessage( + AnnotationsAnalyzer.class, key)); + } + } + + private void checkInitializerMethod( ExecutableElement element, + TypeElement parent, CdiAnalysisResult result ) + { + Set modifiers = element.getModifiers(); + boolean isAbstract = modifiers.contains( Modifier.ABSTRACT ); + boolean isStatic = modifiers.contains( Modifier.STATIC ); + if ( isAbstract || isStatic ){ + String key = isAbstract? "ERR_AbstractInitMethod": + "ERR_StaticInitMethod"; // NOI18N + result.addError( element, NbBundle.getMessage( + AnnotationsAnalyzer.class, key )); + } + TypeMirror method = result.getInfo().getTypes().asMemberOf( + (DeclaredType)parent.asType() , element); + if ( method instanceof ExecutableType ){ + List typeVariables = + ((ExecutableType)method).getTypeVariables(); + if ( typeVariables != null && typeVariables.size() > 0 ){ + result.addError( element, NbBundle.getMessage( + AnnotationsAnalyzer.class, "ERR_GenericInitMethod" ));// NOI18N + } + } + } + + private void checkAbstractMethod( ExecutableElement element, + CdiAnalysisResult result ,boolean isProducer, boolean isDisposer ) + { + if ( isProducer || isDisposer ){ + String key = isProducer? "ERR_AbstractProducerMethod": + "ERR_AbstractDisposerMethod"; // NOI18N + Set modifiers = element.getModifiers(); + if ( modifiers.contains( Modifier.ABSTRACT )){ + result.addError( element, NbBundle.getMessage( + AnnotationsAnalyzer.class, key )); + } + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/Bundle.properties b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/Bundle.properties new file mode 100644 index 000000000000..aee689a71b11 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/Bundle.properties @@ -0,0 +1,87 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +ERR_BadRestritedMethodType=Bean class of method return type specifies @Typed \ +annotation, and the value member specifies a class which does not correspond \ +to a type in the unrestricted set of bean types of a bean. +ERR_BothAnnotationsMethod=The method has both {0} and {1} annotations. +ERR_ManyObservesParameter=An observer method should have only one parameter \ +annotated by @Observes. +ERR_ManyDisposesParameter=A disposer method should have only one parameter \ +annotated by @Disposes. +ERR_AbstractProducerMethod=A producer method must be a non-abstract method of a \ +managed bean class or session bean class. +ERR_AbstractDisposerMethod=A disposer method must be a non-abstract method of a \ +managed bean class or session bean class. +ERR_WrongDelegateMethod=A delegate injection point must be initializer method \ +parameter or bean constructor method parameter. +ERR_DelegateIsNotInDecorator=Parameter is declared as @Delegate but its enclosing \ +type element is not a decorator. +ERR_FinalInterceptedMethod=The non-static, non-private method of a bean class of a \ +managed bean is final and declares a method level interceptor binding. +ERR_FinalInterceptedClass=The non-static, non-private method of a final bean class of a \ +managed bean declares a method level interceptor binding. + +ERR_ProducerReturnIsTypeVar=A producer method return type should not be a type variable. +ERR_ProducerReturnHasWildcard=A producer method return type should not contain a wildcard type parameter. + +ERR_WrongScopeParameterizedProducerReturn=The producer method return type is a \ +parameterized type with a type variable and has scope {0} (should be @Dependent). +ERR_StaticSpecializesProducer=A producer method annotated with @Specializes must be non-static. +ERR_NoDirectSpecializedProducer=A producer method annotated with @Specializes must \ +directly override another producer method. + +ERR_AbstractInitMethod=An initializer method should be a non-abstract. +ERR_StaticInitMethod=An initializer method should be a non-static. +ERR_GenericInitMethod=An initializer method should not be a generic. + +ERR_ParameterNamedInjectionPoint=An injection point has a @Named annotation \ +without value member specified. + +ERR_WrongQualifierInjectionPointMeta=An injection point has type InjectionPoint \ +and qualifier @Default but bean declares not @Dependent scope. + +ERR_BadSpecializesMethod=Method specializes another method but its bean type does \ +not have all bean types of specialized method. + +ERR_FinalDecoratedBean=Delegate injection point matches a managed bean {0} which \ +class is declared final. +ERR_FinalMethodDecoratedBean=Delegate injection point matches a managed bean {0} \ +with final method {1} which is implemented by decorator. +ERR_DelegateTypeHasNoDecoratedType=The delegate type of a decorator must implement \ +or extend every decorated type of decorator. + +WARN_CallbackInterceptorBinding=Interceptor bindings for lifecycle callback methods \ +includes only the interceptor bindings declared or inherited by the bean at the class \ +level. +ERR_LifecycleInterceptorTarget=An interceptor for lifecycle callbacks may only \ +declare interceptor binding types that are defined as @Target(TYPE). Interceptor {0} \ +declares mismatch interceptor binding {1}. + +ERR_ProducerNotBusiness=A producer non-static method of a session bean class \ +should be a business method of the session bean. + +ERR_DisposerNotBusiness=A disposer non-static method of a session bean class \ +should be a business method of the session bean. + +ERR_ObserverNotBusiness=An observer non-static method of a session bean class \ +should be a business method of the session bean. + +WARN_NamedInjectionPoint=The use of @Named as an injection point qualifier is not recommended. + +ERR_NotPassivationProducerReturn=Producer method has a passivating scope {0} and should be \ +passivation capable. But its return type is declared final and does not implement Serializable. \ No newline at end of file diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/DelegateMethodAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/DelegateMethodAnalyzer.java new file mode 100644 index 000000000000..32b766b0a1d2 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/DelegateMethodAnalyzer.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.method; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.CdiEditorAnalysisFactory; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.MethodElementAnalyzer.MethodAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.field.DelegateFieldAnalizer; +import org.netbeans.modules.jakarta.web.beans.hints.EditorAnnotationsHelper; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class DelegateMethodAnalyzer implements MethodAnalyzer { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.MethodElementAnalyzer.MethodAnalyzer#analyze(javax.lang.model.element.ExecutableElement, javax.lang.model.type.TypeMirror, javax.lang.model.element.TypeElement, java.util.concurrent.atomic.AtomicBoolean, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer.Result) + */ + @Override + public void analyze( ExecutableElement element, TypeMirror returnType, + TypeElement parent, AtomicBoolean cancel, CdiAnalysisResult result ) + { + List parameters = element.getParameters(); + int i=0; + for (VariableElement param : parameters) { + if (cancel.get()) { + return; + } + if (AnnotationUtil.hasAnnotation(param, + AnnotationUtil.DELEGATE_FQN, result.getInfo())) + { + result.requireCdiEnabled(element); + if (cancel.get()) { + return; + } + checkMethodDefinition(element, param, result ); + if (cancel.get()) { + return; + } + checkClassDefinition(parent, element, param, result ); + if (cancel.get()) { + return; + } + checkDelegateType(param, i, element, parent, result ); + VariableElement var = CdiEditorAnalysisFactory.resolveParameter( + param, element, result.getInfo()); + EditorAnnotationsHelper helper = EditorAnnotationsHelper. + getInstance(result); + if ( helper != null ){ + helper.addInjectionPoint(result, var); + } + } + i++; + } + } + + private void checkClassDefinition( TypeElement parent, + ExecutableElement element, VariableElement param, + CdiAnalysisResult result) + { + if ( !AnnotationUtil.hasAnnotation(parent, AnnotationUtil.DECORATOR, + result.getInfo())) + { + result.addError( param, + NbBundle.getMessage(DelegateFieldAnalizer.class, + "ERR_DelegateIsNotInDecorator")); // NOI18N + } + } + + private void checkDelegateType( VariableElement element, int i, + ExecutableElement method, TypeElement parent, + CdiAnalysisResult result ) + { + ExecutableType methodType = (ExecutableType) result.getInfo().getTypes() + .asMemberOf((DeclaredType) parent.asType(), method); + List parameterTypes = methodType + .getParameterTypes(); + TypeMirror parameterType = parameterTypes.get(i); + Collection decoratedTypes = DelegateFieldAnalizer + .getDecoratedTypes(parent, result.getInfo()); + for (TypeMirror decoratedType : decoratedTypes) { + if (!result.getInfo().getTypes().isSubtype(parameterType, decoratedType)) { + result.addError(element, NbBundle.getMessage( + DelegateMethodAnalyzer.class, + "ERR_DelegateTypeHasNoDecoratedType")); // NOI18N + return; + } + } + } + + private void checkMethodDefinition( ExecutableElement element, + VariableElement param, CdiAnalysisResult result ) + { + if ( element.getKind() == ElementKind.CONSTRUCTOR ){ + return; + } + if ( !AnnotationUtil.hasAnnotation(element, AnnotationUtil.INJECT_FQN, + result.getInfo())) + { + result.addError( param, + NbBundle.getMessage(DelegateMethodAnalyzer.class, + "ERR_WrongDelegateMethod")); // NOI18N + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/InjectionPointParameterAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/InjectionPointParameterAnalyzer.java new file mode 100644 index 000000000000..9723ca5f4f37 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/InjectionPointParameterAnalyzer.java @@ -0,0 +1,257 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.method; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationHelper; +import org.netbeans.modules.jakarta.web.beans.analysis.CdiEditorAnalysisFactory; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractDecoratorAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.MethodModelAnalyzer.MethodAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.field.InjectionPointAnalyzer; +import org.netbeans.modules.jakarta.web.beans.api.model.CdiException; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult.ResultKind; +import org.netbeans.modules.jakarta.web.beans.api.model.InjectionPointDefinitionError; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.hints.EditorAnnotationsHelper; +import org.netbeans.spi.editor.hints.Severity; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class InjectionPointParameterAnalyzer + extends AbstractDecoratorAnalyzer implements MethodAnalyzer +{ + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.MethodModelAnalyzer.MethodAnalyzer#analyze(javax.lang.model.element.ExecutableElement, javax.lang.model.type.TypeMirror, javax.lang.model.element.TypeElement, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.util.concurrent.atomic.AtomicBoolean, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result) + */ + @Override + public void analyze( ExecutableElement element, TypeMirror returnType, + TypeElement parent, WebBeansModel model , + AtomicBoolean cancel , Result result ) + { + for (VariableElement var : element.getParameters()) { + if (cancel.get()) { + return; + } + try { + if (model.isInjectionPoint(var)) { + boolean isDelegate = false; + result.requireCdiEnabled(element, model); + if ( cancel.get() ){ + return; + } + if (!model.isDynamicInjectionPoint(var)) { + isDelegate =AnnotationUtil.isDelegate(var, parent, model); + if (!checkBuiltInBeans(var, + getParameterType(var, element, parent, + model.getCompilationController()), + model, cancel)) + { + DependencyInjectionResult res = model + .lookupInjectables(var, + (DeclaredType) parent.asType(), cancel); + checkResult(res, element, var, model, result); + if (isDelegate) { + analyzeDecoratedBeans(res, var, element, + parent, model, result); + } + } + } + if ( cancel.get()){ + return; + } + checkName(element, var, model,result ); + if ( cancel.get()){ + return; + } + checkInjectionPointMetadata( var, element, parent , model , + cancel , result ); + if ( isDelegate || AnnotationUtil.hasAnnotation(element, + AnnotationUtil.DELEGATE_FQN, model.getCompilationController())) + { + return; + } + else { + VariableElement param = CdiEditorAnalysisFactory. + resolveParameter(var, element, result.getInfo()); + EditorAnnotationsHelper helper = EditorAnnotationsHelper. + getInstance(result); + if ( helper != null ){ + helper.addInjectionPoint(result, param); + } + } + } + } + catch( InjectionPointDefinitionError e ){ + result.requireCdiEnabled(element, model); + informInjectionPointDefError(e, element, model, result ); + } + } + + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractDecoratorAnalyzer#addClassError(javax.lang.model.element.VariableElement, java.lang.Object, javax.lang.model.element.TypeElement, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, org.netbeans.api.java.source.CompilationInfo, java.util.List) + */ + @Override + protected void addClassError( VariableElement element, ExecutableElement method, + TypeElement decoratedBean, WebBeansModel model, + Result result ) + { + result.addError( element , method, model, + NbBundle.getMessage(InjectionPointParameterAnalyzer.class, + "ERR_FinalDecoratedBean", // NOI18N + decoratedBean.getQualifiedName().toString())); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractDecoratorAnalyzer#addMethodError(javax.lang.model.element.VariableElement, java.lang.Object, javax.lang.model.element.TypeElement, javax.lang.model.element.Element, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result) + */ + @Override + protected void addMethodError( VariableElement element, + ExecutableElement method, TypeElement decoratedBean, + Element decoratedMethod, WebBeansModel model, Result result ) + { + result.addError( + element, method, model, NbBundle.getMessage( + InjectionPointParameterAnalyzer.class, + "ERR_FinalMethodDecoratedBean", // NOI18N + decoratedBean.getQualifiedName().toString(), + decoratedMethod.getSimpleName().toString())); + } + + private TypeMirror getParameterType( VariableElement var, + ExecutableElement element, TypeElement parent , + CompilationController controller ) + { + ExecutableType method = (ExecutableType)controller.getTypes().asMemberOf( + (DeclaredType)parent.asType(), element); + List parameterTypes = method.getParameterTypes(); + List parameters = element.getParameters(); + int paramIndex = parameters.indexOf(var); + return parameterTypes.get(paramIndex); + } + + private void checkInjectionPointMetadata( VariableElement var, + ExecutableElement method, TypeElement parent, WebBeansModel model, + AtomicBoolean cancel , Result result ) + { + TypeElement injectionPointType = model.getCompilationController() + .getElements().getTypeElement(AnnotationUtil.INJECTION_POINT); + if (injectionPointType == null) { + return; + } + Element varElement = model.getCompilationController().getTypes() + .asElement(var.asType()); + if (!injectionPointType.equals(varElement)) { + return; + } + if (cancel.get()) { + return; + } + List qualifiers = model.getQualifiers(varElement, + true); + AnnotationHelper helper = new AnnotationHelper( + model.getCompilationController()); + Map qualifiersFqns = helper + .getAnnotationsByType(qualifiers); + boolean hasDefault = model.hasImplicitDefaultQualifier(varElement); + if (!hasDefault + && qualifiersFqns.containsKey(AnnotationUtil.DEFAULT_FQN)) + { + hasDefault = true; + } + if (!hasDefault || cancel.get()) { + return; + } + try { + String scope = model.getScope(parent); + if (scope != null && !AnnotationUtil.DEPENDENT.equals(scope)) { + result.addError(var, method, model, + NbBundle.getMessage(InjectionPointParameterAnalyzer.class,"ERR_WrongQualifierInjectionPointMeta")); // NOI18N + } + } + catch (CdiException e) { + // this exception will be handled in the appropriate scope analyzer + return; + } + } + + private void checkName( ExecutableElement element, VariableElement var, + WebBeansModel model, Result result) + { + AnnotationMirror annotation = AnnotationUtil.getAnnotationMirror( + var , AnnotationUtil.NAMED, model.getCompilationController()); + if ( annotation!= null){ + result.addNotification( Severity.WARNING , var, element , model, + NbBundle.getMessage(InjectionPointAnalyzer.class, + "WARN_NamedInjectionPoint")); // NOI18N + if ( annotation.getElementValues().size() == 0 ){ + result.addError(var, element, model, + NbBundle.getMessage( InjectionPointParameterAnalyzer.class, + "ERR_ParameterNamedInjectionPoint")); // NOI18N + } + } + } + + private void checkResult( DependencyInjectionResult res , + ExecutableElement method , VariableElement element, WebBeansModel model, + Result result ) + { + if ( res instanceof DependencyInjectionResult.Error ){ + ResultKind kind = res.getKind(); + Severity severity = Severity.WARNING; + if ( kind == DependencyInjectionResult.ResultKind.DEFINITION_ERROR){ + severity = Severity.ERROR; + } + String message = ((DependencyInjectionResult.Error)res).getMessage(); + result.addNotification(severity, element , method , + model, message); + } + } + + private void informInjectionPointDefError(InjectionPointDefinitionError exception , + Element element, WebBeansModel model, + Result result ) + { + result.addError(element, model, exception.getMessage()); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/InterceptedMethodAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/InterceptedMethodAnalyzer.java new file mode 100644 index 000000000000..27eb796874f2 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/InterceptedMethodAnalyzer.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.method; + +import java.lang.annotation.ElementType; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Types; +import org.netbeans.api.java.source.CompilationController; + +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationHelper; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractInterceptedElementAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.MethodModelAnalyzer.MethodAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.TargetAnalyzer; +import org.netbeans.modules.jakarta.web.beans.api.model.InterceptorsResult; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.hints.EditorAnnotationsHelper; +import org.netbeans.spi.editor.hints.Severity; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class InterceptedMethodAnalyzer extends AbstractInterceptedElementAnalyzer + implements MethodAnalyzer +{ + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.MethodModelAnalyzer.MethodAnalyzer#analyze(javax.lang.model.element.ExecutableElement, javax.lang.model.type.TypeMirror, javax.lang.model.element.TypeElement, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.util.List, org.netbeans.api.java.source.CompilationInfo, java.util.concurrent.atomic.AtomicBoolean) + */ + @Override + public void analyze( ExecutableElement element, TypeMirror returnType, + TypeElement parent, WebBeansModel model, + AtomicBoolean cancel , Result result ) + { + boolean hasInterceptorBindings = hasInterceptorBindings(element, model); + if ( hasInterceptorBindings ){ + result.requireCdiEnabled(element, model); + EditorAnnotationsHelper helper = EditorAnnotationsHelper.getInstance(result); + ElementHandle handle = ElementHandle.create(element); + if ( helper != null ){ + helper.addInterceptedMethod(result, handle.resolve( result.getInfo())); + } + } + if (AnnotationUtil.isLifecycleCallback(element, model.getCompilationController() )) { + if (hasInterceptorBindings) { + result.addNotification( Severity.WARNING, element, model, + NbBundle.getMessage(InterceptedMethodAnalyzer.class, + "WARN_CallbackInterceptorBinding")); // NOI18N + } + if (cancel.get()) { + return; + } + InterceptorsResult interceptorResult = model + .getInterceptors(element); + List interceptors = interceptorResult + .getResolvedInterceptors(); + AnnotationHelper helper = null; + if ( interceptors.size() >0 ){ + helper = new AnnotationHelper(model.getCompilationController()); + } + for (TypeElement interceptor : interceptors) { + if (isLifecycleCallbackInterceptor(interceptor, model.getCompilationController())) { + Collection interceptorBindings = model + .getInterceptorBindings(interceptor); + for (AnnotationMirror annotationMirror : interceptorBindings) { + Element iBinding = model.getCompilationController().getTypes(). + asElement( annotationMirror.getAnnotationType() ); + if ( !( iBinding instanceof TypeElement )) { + continue; + } + Set declaredTargetTypes = TargetAnalyzer. + getDeclaredTargetTypes(helper, (TypeElement)iBinding); + if ( declaredTargetTypes.size() != 1 || + !declaredTargetTypes.contains(ElementType.TYPE)) + { + result.addError(element, model, + NbBundle.getMessage(InterceptedMethodAnalyzer.class, + "ERR_LifecycleInterceptorTarget" , // NOI18N + interceptor.getQualifiedName().toString(), + ((TypeElement)iBinding).getQualifiedName().toString())); + } + } + } + } + } + if (cancel.get()) { + return; + } + + Set modifiers = element.getModifiers(); + if ( modifiers.contains( Modifier.STATIC ) || + modifiers.contains( Modifier.PRIVATE)) + { + return; + } + boolean finalMethod = modifiers.contains( Modifier.FINAL ); + boolean finalClass = parent.getModifiers().contains( Modifier.FINAL); + if ( !finalMethod && !finalClass ){ + return; + } + if ( cancel.get() ){ + return; + } + if ( hasInterceptorBindings){ + if ( finalMethod ){ + result.addError(element, model, + NbBundle.getMessage( + InterceptedMethodAnalyzer.class, + "ERR_FinalInterceptedMethod")); // NOI18N + } + if ( finalClass && !AnnotationUtil.hasAnnotation(parent, + AnnotationUtil.INTERCEPTOR, model.getCompilationController())) + { + result.addError(element, model, + NbBundle.getMessage( + InterceptedMethodAnalyzer.class, + "ERR_FinalInterceptedClass")); // NOI18N + } + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractInterceptedElementAnalyzer#getInterceptorBindings(javax.lang.model.element.Element, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel) + */ + @Override + protected Set getInterceptorBindings( Element element, + WebBeansModel model ) + { + Set iBindings = super.getInterceptorBindings(element, model); + List annotations = model + .getCompilationController().getElements() + .getAllAnnotationMirrors(element); + iBindings.retainAll(annotations); + return iBindings; + } + + private static boolean isLifecycleCallbackInterceptor(TypeElement interceptor, CompilationController info) { + for (Element e : interceptor.getEnclosedElements()) { + if (e.getKind() == ElementKind.METHOD && e instanceof ExecutableElement) { + if (AnnotationUtil.isLifecycleCallback((ExecutableElement) e, info)) { + return true; + } + } + } + TypeMirror tm = interceptor.getSuperclass(); + if (tm.getKind() == TypeKind.DECLARED) { + Element e = info.getTypes().asElement(tm); + if (e instanceof TypeElement) { + return isLifecycleCallbackInterceptor((TypeElement) e, info); + } + } + + return false; + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/ProducerMethodAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/ProducerMethodAnalyzer.java new file mode 100644 index 000000000000..3c288e3ce08e --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/ProducerMethodAnalyzer.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.method; + +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractProducerAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.MethodElementAnalyzer.MethodAnalyzer; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class ProducerMethodAnalyzer extends AbstractProducerAnalyzer + implements MethodAnalyzer +{ + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.MethodElementAnalyzer.MethodAnalyzer#analyze(javax.lang.model.element.ExecutableElement, javax.lang.model.type.TypeMirror, javax.lang.model.element.TypeElement, java.util.concurrent.atomic.AtomicBoolean, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer.Result) + */ + @Override + public void analyze( ExecutableElement element, TypeMirror returnType, + TypeElement parent, AtomicBoolean cancel , CdiAnalysisResult result ) + { + if ( !AnnotationUtil.hasAnnotation(element, AnnotationUtil.PRODUCES_FQN, + result.getInfo() )) + { + return; + } + result.requireCdiEnabled(element); + if ( cancel.get() ){ + return; + } + checkType( element, returnType, result ); + if ( cancel.get() ){ + return; + } + checkSpecializes( element , result ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractProducerAnalyzer#hasTypeVar(javax.lang.model.element.Element, javax.lang.model.type.TypeMirror, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer.Result) + */ + @Override + protected void hasTypeVar( Element element, TypeMirror type, + CdiAnalysisResult result) + { + result.addError( element, NbBundle.getMessage( + ProducerMethodAnalyzer.class, "ERR_ProducerReturnIsTypeVar")); // NOI18N + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractProducerAnalyzer#hasWildCard(javax.lang.model.element.Element, javax.lang.model.type.TypeMirror, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer.Result) + */ + @Override + protected void hasWildCard( Element element, TypeMirror type, + CdiAnalysisResult result ) + { + result.addError(element, NbBundle.getMessage( + ProducerMethodAnalyzer.class,"ERR_ProducerReturnHasWildcard")); // NOI18N + } + + private void checkSpecializes(ExecutableElement element, CdiAnalysisResult result ) + { + if ( !AnnotationUtil.hasAnnotation(element, AnnotationUtil.SPECIALIZES, + result.getInfo() )) + { + return; + } + Set modifiers = element.getModifiers(); + if ( modifiers.contains( Modifier.STATIC )){ + result.addError( element, NbBundle.getMessage( + ProducerMethodAnalyzer.class, + "ERR_StaticSpecializesProducer")); // NOI18N + } + CompilationInfo compInfo = result.getInfo(); + ExecutableElement overridenMethod = compInfo.getElementUtilities(). + getOverriddenMethod( element ); + if ( overridenMethod == null ){ + return; + } + TypeElement superClass = compInfo.getElementUtilities(). + enclosingTypeElement( overridenMethod ); + TypeElement containingClass = compInfo.getElementUtilities(). + enclosingTypeElement( element ); + TypeMirror typeDirectSuper = containingClass.getSuperclass(); + if ( !superClass.equals(compInfo.getTypes().asElement(typeDirectSuper)) || + !AnnotationUtil.hasAnnotation(overridenMethod, + AnnotationUtil.PRODUCES_FQN, compInfo)) + { + result.addError( element, NbBundle.getMessage( + ProducerMethodAnalyzer.class, + "ERR_NoDirectSpecializedProducer")); // NOI18N + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/ScopedMethodAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/ScopedMethodAnalyzer.java new file mode 100644 index 000000000000..dc84c12c454b --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/ScopedMethodAnalyzer.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.method; + +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractScopedAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.MethodModelAnalyzer.MethodAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class ScopedMethodAnalyzer extends AbstractScopedAnalyzer implements + MethodAnalyzer +{ + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.MethodModelAnalyzer.MethodAnalyzer#analyze(javax.lang.model.element.ExecutableElement, javax.lang.model.type.TypeMirror, javax.lang.model.element.TypeElement, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.util.concurrent.atomic.AtomicBoolean, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result) + */ + @Override + public void analyze( ExecutableElement element, TypeMirror returnType, + TypeElement parent, WebBeansModel model, + AtomicBoolean cancel, Result result ) + { + if ( AnnotationUtil.hasAnnotation(element, AnnotationUtil.PRODUCES_FQN, + model.getCompilationController())) + { + result.requireCdiEnabled(element,model); + analyzeScope(element, model, cancel, result ); + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractScopedAnalyzer#checkScope(javax.lang.model.element.TypeElement, javax.lang.model.element.Element, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.util.concurrent.atomic.AtomicBoolean, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result) + */ + @Override + protected void checkScope( TypeElement scopeElement, Element element, + WebBeansModel model, AtomicBoolean cancel, Result result ) + { + if ( scopeElement.getQualifiedName().contentEquals( AnnotationUtil.DEPENDENT)){ + return; + } + TypeMirror methodType = element.asType(); + if ( methodType instanceof ExecutableType ){ + TypeMirror returnType = ((ExecutableType)methodType).getReturnType(); + if ( cancel.get() ){ + return; + } + if ( hasTypeVarParameter( returnType )){ + result.addError( element, model, + NbBundle.getMessage(ScopedMethodAnalyzer.class, + "ERR_WrongScopeParameterizedProducerReturn", // NOI18N + scopeElement.getQualifiedName().toString())); + } + } + if ( cancel.get() ){ + return; + } + checkPassivationCapable( scopeElement , element , model , result ); + } + + private void checkPassivationCapable( TypeElement scopeElement, + Element element, WebBeansModel model, Result result ) + { + if ( !isPassivatingScope(scopeElement, model) ){ + return; + } + TypeMirror returnType = ((ExecutableElement)element).getReturnType(); + if ( returnType == null ){ + return; + } + if ( returnType.getKind().isPrimitive() ){ + return; + } + if ( isSerializable(returnType, model)){ + return; + } + Element returnTypeElement = model.getCompilationController().getTypes(). + asElement( returnType ); + if ( returnTypeElement == null ){ + return; + } + if ( returnTypeElement.getModifiers().contains( Modifier.FINAL )){ + result.addError( element, model, + NbBundle.getMessage(ScopedMethodAnalyzer.class, + "ERR_NotPassivationProducerReturn", // NOI18N + scopeElement.getQualifiedName().toString())); + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/TypedMethodAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/TypedMethodAnalyzer.java new file mode 100644 index 000000000000..dd98332aa42e --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/method/TypedMethodAnalyzer.java @@ -0,0 +1,205 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.method; + +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.PrimitiveType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractTypedAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.MethodElementAnalyzer.MethodAnalyzer; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class TypedMethodAnalyzer extends AbstractTypedAnalyzer implements + MethodAnalyzer +{ + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.MethodElementAnalyzer.MethodAnalyzer#analyze(javax.lang.model.element.ExecutableElement, javax.lang.model.type.TypeMirror, javax.lang.model.element.TypeElement, java.util.concurrent.atomic.AtomicBoolean, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer.Result) + */ + @Override + public void analyze( ExecutableElement element, TypeMirror returnType, + TypeElement parent, AtomicBoolean cancel , CdiAnalysisResult result ) + { + analyze(element, returnType, cancel , result ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractTypedAnalyzer#addError(javax.lang.model.element.Element, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer.Result) + */ + @Override + protected void addError( Element element, CdiAnalysisResult result ) + { + result.addError( element, NbBundle.getMessage( + TypedMethodAnalyzer.class, "ERR_BadRestritedMethodType")); // NOI18N + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.AbstractTypedAnalyzer#hasBeanType(javax.lang.model.element.Element, javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror, org.netbeans.api.java.source.CompilationInfo) + */ + @Override + protected boolean hasBeanType( Element subject, TypeMirror returnType, + TypeMirror requiredBeanType, CompilationInfo compInfo ) + { + return compInfo.getTypes().isSubtype(returnType, requiredBeanType); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractTypedAnalyzer#checkSpecializes(javax.lang.model.element.Element, javax.lang.model.type.TypeMirror, java.util.List, java.util.concurrent.atomic.AtomicBoolean, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer.Result) + */ + @Override + protected void checkSpecializes( Element element, TypeMirror elementType, + List restrictedTypes, AtomicBoolean cancel , CdiAnalysisResult result ) + { + CompilationInfo compInfo = result.getInfo(); + if (!AnnotationUtil.hasAnnotation(element, AnnotationUtil.PRODUCES_FQN, + compInfo)) + { + return; + } + ExecutableElement method = (ExecutableElement)element; + ExecutableElement overriddenMethod = compInfo.getElementUtilities(). + getOverriddenMethod(method); + if ( overriddenMethod == null ){ + return; + } + TypeElement clazz = compInfo.getElementUtilities(). + enclosingTypeElement(method); + TypeMirror superType = clazz.getSuperclass(); + TypeElement superClass = compInfo.getElementUtilities(). + enclosingTypeElement(overriddenMethod); + if ( !superClass.equals( compInfo.getTypes().asElement( superType))){ + return; + } + if ( cancel.get()){ + return; + } + List restrictedSuper = getRestrictedTypes(overriddenMethod, + compInfo, cancel); + if ( cancel.get()){ + return; + } + if ( restrictedSuper == null ) { + if (!hasUnrestrictedOverridenType(elementType, + restrictedTypes, compInfo,overriddenMethod, superClass) ) + { + result.addError( element, NbBundle.getMessage( + TypedMethodAnalyzer.class, "ERR_BadSpecializesMethod")); // NOI18N + } + } + else { + if (!hasRestrictedType(elementType, restrictedTypes, compInfo, + restrictedSuper)) + { + result.addError( element, NbBundle.getMessage( + TypedMethodAnalyzer.class, "ERR_BadSpecializesMethod")); // NOI18N + } + } + } + + private boolean hasRestrictedType( TypeMirror elementType, + List restrictedTypes, CompilationInfo compInfo, + List restrictedSuper ) + { + if ( elementType.getKind() == TypeKind.ARRAY ){ + for( TypeMirror mirror : restrictedSuper ){ + boolean found = false; + for( TypeMirror restrictedType : restrictedTypes ){ + if ( compInfo.getTypes().isSameType( restrictedType, mirror)){ + found = true; + break; + } + } + if ( !found ){ + return false; + } + } + return true; + } + else { + Set specializedBeanTypes = getElements( + restrictedSuper, compInfo); + Set restrictedElements = getElements(restrictedTypes, + compInfo); + restrictedElements.add( compInfo.getElements().getTypeElement( + Object.class.getCanonicalName())); + return restrictedElements.containsAll( specializedBeanTypes ); + } + } + + private boolean hasUnrestrictedOverridenType( TypeMirror elementType, + List restrictedTypes, CompilationInfo compInfo, + ExecutableElement overriddenMethod, TypeElement superClass ) + { + TypeMirror methodType = compInfo.getTypes().asMemberOf( + (DeclaredType)superClass.asType(), overriddenMethod); + TypeMirror returnOverriden = ((ExecutableType)methodType).getReturnType(); + if ( elementType.getKind() == TypeKind.ARRAY ){ + for( TypeMirror mirror : restrictedTypes ){ + if ( compInfo.getTypes().isSameType( mirror, returnOverriden)){ + return true; + } + } + return false; + } + else if ( returnOverriden.getKind().isPrimitive() ) { + TypeElement boxed = compInfo.getTypes().boxedClass( + (PrimitiveType)returnOverriden); + return hasUnrestrictedType(boxed, restrictedTypes, compInfo); + } + else if ( returnOverriden instanceof DeclaredType ){ + Element returnElement = compInfo.getTypes().asElement( returnOverriden); + if ( returnElement instanceof TypeElement ){ + return hasUnrestrictedType((TypeElement)returnElement, + restrictedTypes, compInfo); + } + } + return true; + } + + private boolean hasUnrestrictedType( TypeElement overriden, + List restrictedTypes,CompilationInfo compInfo ) + { + Set specializedBeanTypes = getUnrestrictedBeanTypes( + overriden, compInfo); + Set restrictedElements = getElements(restrictedTypes, + compInfo); + restrictedElements.add( compInfo.getElements().getTypeElement( + Object.class.getCanonicalName())); + return restrictedElements.containsAll(specializedBeanTypes); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/AnnotationsAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/AnnotationsAnalyzer.java new file mode 100644 index 000000000000..323460b97166 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/AnnotationsAnalyzer.java @@ -0,0 +1,275 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.type; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.util.ElementFilter; + +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ClassElementAnalyzer.ClassAnalyzer; +import org.openide.util.NbBundle; +import org.netbeans.spi.editor.hints.Severity; + + +/** + * @author ads + * + */ +public class AnnotationsAnalyzer implements ClassAnalyzer { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ClassElementAnalyzer.ClassAnalyzer#analyze(javax.lang.model.element.TypeElement, javax.lang.model.element.TypeElement, org.netbeans.api.java.source.CompilationInfo, java.util.List, java.util.concurrent.atomic.AtomicBoolean) + */ + @Override + public void analyze( TypeElement element, TypeElement parent, + AtomicBoolean cancel, CdiAnalysisResult result ) + { + checkDecoratorInterceptor( element , cancel, result ); + } + + private void checkDecoratorInterceptor( TypeElement element, + AtomicBoolean cancel , CdiAnalysisResult result ) + { + CompilationInfo compInfo = result.getInfo(); + boolean isDecorator = AnnotationUtil.hasAnnotation(element, + AnnotationUtil.DECORATOR, compInfo); + boolean isInterceptor = AnnotationUtil.hasAnnotation(element, + AnnotationUtil.INTERCEPTOR, compInfo); + if ( isDecorator && isInterceptor ){ + result.addError( element, NbBundle.getMessage( + AnnotationsAnalyzer.class, "ERR_DecoratorInterceptor"));// NOI18N + } + if ( isDecorator || isInterceptor ){ + result.requireCdiEnabled(element); + if ( cancel.get() ){ + return; + } + checkProducerFields( element , isDecorator , result); + if ( cancel.get() ){ + return; + } + checkMethods( element , isDecorator , result); + if ( cancel.get() ){ + return; + } + checkSession( element , result); + if ( cancel.get() ){ + return; + } + checkNamed( element , result ); + if ( cancel.get() ){ + return; + } + checkAlternatives(element , result ); + if ( cancel.get() ){ + return; + } + checkSpecializes( element , result ); + } + if ( isDecorator ){ + if ( cancel.get() ){ + return; + } + checkDelegateInjectionPoint(element , result); + } + } + + private void checkSpecializes( TypeElement element, CdiAnalysisResult result ) + { + if ( AnnotationUtil.hasAnnotation(element, AnnotationUtil.SPECIALIZES, + result.getInfo()) ) + { + result.addNotification(Severity.WARNING, element, NbBundle.getMessage( + AnnotationsAnalyzer.class, + "WARN_SpecializesInterceptorDecorator")); // NOI18N + } + } + + private void checkAlternatives( TypeElement element, + CdiAnalysisResult result ) + { + if ( AnnotationUtil.hasAnnotation(element, AnnotationUtil.ALTERNATVE, + result.getInfo())) + { + result.addNotification(Severity.WARNING, element, NbBundle.getMessage( + AnnotationsAnalyzer.class, + "WARN_AlternativeInterceptorDecorator")); // NOI18N + } + } + + private void checkNamed( TypeElement element, CdiAnalysisResult result ) { + if ( AnnotationUtil.hasAnnotation(element, AnnotationUtil.NAMED, + result.getInfo())) + { + result.addNotification(Severity.WARNING, element, NbBundle.getMessage( + AnnotationsAnalyzer.class, "WARN_NamedInterceptorDecorator")); // NOI18N + } + } + + private void checkDelegateInjectionPoint( TypeElement element, + CdiAnalysisResult result ) + { + CompilationInfo compInfo = result.getInfo(); + List enclosedElements = element.getEnclosedElements(); + int count = 0; + for (Element child : enclosedElements) { + if ( child.getKind() == ElementKind.CONSTRUCTOR ) + { + count +=delegateInjectionPointCount(child, compInfo); + } + else if ( ! AnnotationUtil.hasAnnotation(child, AnnotationUtil.INJECT_FQN, + compInfo )) + { + continue; + } + if ( child.getKind() == ElementKind.FIELD && AnnotationUtil. + hasAnnotation(child, AnnotationUtil.DELEGATE_FQN, compInfo )) + { + count++; + } + else if ( child.getKind() ==ElementKind.METHOD ) + { + count+=delegateInjectionPointCount(child, compInfo); + } + } + if ( count != 1){ + result.addError( element, NbBundle.getMessage( + AnnotationsAnalyzer.class, "ERR_IncorrectDelegateCount")); // NOI18N + } + } + + private int delegateInjectionPointCount(Element element , + CompilationInfo compInfo) + { + int result=0; + ExecutableElement method = (ExecutableElement)element; + List parameters = method.getParameters(); + for (VariableElement par : parameters) { + if ( AnnotationUtil.hasAnnotation(par, AnnotationUtil.DELEGATE_FQN, + compInfo)) + { + result++; + } + } + return result; + } + + private void checkSession( TypeElement element, + CdiAnalysisResult result ) + { + if ( AnnotationUtil.isSessionBean(element, result.getInfo()) ) + { + result.addError( element, NbBundle.getMessage( + AnnotationsAnalyzer.class, "ERR_SesssionBeanID")); // NOI18N + } + } + + private void checkMethods( TypeElement element, boolean isDecorator, + CdiAnalysisResult result ) + { + CompilationInfo compInfo = result.getInfo(); + List methods = ElementFilter.methodsIn( + element.getEnclosedElements()); + for (ExecutableElement method : methods) { + boolean isProducer = AnnotationUtil.hasAnnotation(method, + AnnotationUtil.PRODUCES_FQN, compInfo); + boolean isDisposer = false; + boolean isObserver = false; + List parameters = method.getParameters(); + for (VariableElement param : parameters) { + if ( AnnotationUtil.hasAnnotation( param , AnnotationUtil.DISPOSES_FQN, + compInfo)) + { + isDisposer = true; + break; + } + if ( AnnotationUtil.hasAnnotation( param , AnnotationUtil.OBSERVES_FQN, + compInfo)) + { + isObserver = true; + break; + } + } + if ( isProducer || isDisposer || isObserver ){ + result.addError( element, NbBundle.getMessage( + AnnotationsAnalyzer.class, getMethodErrorKey(isDecorator, + isProducer, isDisposer) , + method.getSimpleName().toString())); + break; + } + } + } + + private String getMethodErrorKey(boolean isDecorator, boolean isProducer, + boolean isDisposer ) + { + String key= null; + if ( isDecorator ){ + if ( isProducer ){ + key = "ERR_DecoratorHasProducerMethod"; // NOI18N + } + else if ( isDisposer ){ + key = "ERR_DecoratorHasDisposerMethod"; // NOI18N + } + else { + key = "ERR_DecoratorHasObserverMethod"; // NOI18N + } + } + else { + if ( isProducer ){ + key = "ERR_InterceptorHasProducerMethod"; // NOI18N + } + else if ( isDisposer ){ + key = "ERR_InterceptorHasDisposerMethod"; // NOI18N + } + else { + key = "ERR_InterceptorHasObserverMethod"; // NOI18N + } + } + return key; + } + + private void checkProducerFields( TypeElement element, boolean isDecorator, + CdiAnalysisResult result ) + { + List fields = ElementFilter.fieldsIn( + element.getEnclosedElements() ); + for (VariableElement field : fields) { + if ( AnnotationUtil.hasAnnotation(field, AnnotationUtil.PRODUCES_FQN, + result.getInfo())) + { + String key= isDecorator ? "ERR_DecoratorHasProducerField": + "ERR_IntrerceptorHasProducerField"; // NOI18N + result.addError( element, NbBundle.getMessage( + AnnotationsAnalyzer.class, key , field.getSimpleName().toString())); + break; + } + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/Bundle.properties b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/Bundle.properties new file mode 100644 index 000000000000..bc718fc65009 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/Bundle.properties @@ -0,0 +1,93 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +ERR_BadRestritedType=Bean class specifies @Typed annotation, and the value member \ +specifies a class which does not correspond to a type in \ +the unrestricted set of bean types of a bean. +ERR_NonStaticInnerType=Non-static inner class cannot be managed bean or \ +superclass of managed bean. +WARN_QualifiedElementExtension=The element is not managed bean: it has \ +qualifiers but implements javax.enterprise.inject.spi.Extension. +WARN_QualifierAbstractClass=The element is not managed bean: it has \ +qualifiers but has abstract modifier. +WARN_QualifierNoCtorClass=The element is not managed bean: it has \ +qualifiers but does not have non-private constructor with no parameters or \ +annotated with @Inject . +ERR_FinalScopedClass=Class is unproxyable: it has normal scope and declared final. +WARN_FinalScopedClassMethod=Final method is declared in class with normal scope. +ERR_DecoratorInterceptor=A managed bean cannot be annotated with both \ +@Interceptor and @Decorator stereotypes. + +ERR_DecoratorHasProducerField=A decorator may not declare producer field "{0}". +ERR_IntrerceptorHasProducerField=An interceptor may not declare producer field "{0}". +ERR_DecoratorHasProducerMethod=A decorator may not declare producer method "{0}". +ERR_DecoratorHasDisposerMethod=A decorator may not declare disposer method "{0}". +ERR_DecoratorHasObserverMethod=A decorator may not declare observer method "{0}". +ERR_InterceptorHasProducerMethod=An interceptor may not declare producer method "{0}". +ERR_InterceptorHasDisposerMethod=An interceptor may not declare disposer method "{0}". +ERR_InterceptorHasObserverMethod=An interceptor may not declare observer method "{0}". + +ERR_InjectedCtor=A bean class should not have more than one constructor annotated @Inject. + +ERR_SesssionBeanID=A bean class of a session bean should not be annotated \ +@Interceptor or @Decorator. + +ERR_InvalidSingletonBeanScope=A singleton bean must belong to either the \ +@ApplicationScoped scope or to the @Dependent pseudo-scope. + +ERR_InvalidStatelessBeanScope=A stateless session bean must belong to the @Dependent pseudo-scope. + +ERR_IncorrectDelegateCount=A decorator must have exactly one delegate injection point. + +ERR_IcorrectScopeWithPublicField=A managed bean with a public field ("{0}") \ +should not declares any scope other than @Dependent. + +ERR_IncorrectScopeForParameterizedBean=A managed bean with a parameterized bean \ +class should not declares any scope other than @Dependent. + +ERR_FinalInterceptedBean=The bean class of a managed bean is final and declares \ +or inherits a class level interceptor binding or a stereotype with interceptor bindings. + +ERR_InterceptedBeanHasFinalMethod=The bean class of a managed bean has non-static, \ +non-private, final method "{0}" and declares or inherits a class level interceptor \ +binding or a stereotype with interceptor bindings. + +ERR_NamedSpecializes=Bean declares name explicitly using @Named but it \ +specializes another bean with name. + +ERR_BadSpecializesBeanType=Bean specializes another bean but it does not \ +have all bean types of specialized bean. + +ERR_InvalidDuplicateIBindings=The set of interceptor bindings has two instances of {0} \ +interceptor binding type and the instances have different values of some annotation member. + +WARN_ScopedDecoratorInterceptor=The @Dependent scope is the only scope which \ +interceptor or decorator could have. The non-portable behavior result otherwise. + +WARN_NamedInterceptorDecorator=An interceptor or decorator should not have a name. \ +Otherwise non-portable behavior results. + +WARN_AlternativeInterceptorDecorator=An interceptor or decorator should not be alternative. \ +Otherwise non-portable behavior results. + +WARN_SpecializesInterceptorDecorator=An interceptor or decorator should not \ +have @Specializes annotation. Otherwise non-portable behavior results. + +ERR_NotPassivationSessionBean=Session bean has a passivating scope {0} and should be \ +passivation capable. Stateless and singleton session beans are not passivation capable. +ERR_NotPassivationManagedBean=Bean has a passivating scope {0} and should be \ +passivation capable. Passivation capable bean should be serializable. diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/CtorsAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/CtorsAnalyzer.java new file mode 100644 index 000000000000..946ea48adaf3 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/CtorsAnalyzer.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.type; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.ElementFilter; + +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ClassElementAnalyzer.ClassAnalyzer; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class CtorsAnalyzer implements ClassAnalyzer { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ClassElementAnalyzer.ClassAnalyzer#analyze(javax.lang.model.element.TypeElement, javax.lang.model.element.TypeElement, org.netbeans.api.java.source.CompilationInfo, java.util.List, java.util.concurrent.atomic.AtomicBoolean) + */ + @Override + public void analyze( TypeElement element, TypeElement parent, + AtomicBoolean cancel, CdiAnalysisResult result ) + { + List constructors = ElementFilter.constructorsIn( + element.getEnclosedElements()); + int injectCtorCount = 0; + for (ExecutableElement ctor : constructors) { + if ( cancel.get() ){ + return; + } + if ( AnnotationUtil.hasAnnotation( ctor , AnnotationUtil.INJECT_FQN, + result.getInfo())) + { + result.requireCdiEnabled( ctor ); + injectCtorCount++; + } + } + if ( injectCtorCount > 1){ + result.addError( element, NbBundle.getMessage( + CtorsAnalyzer.class, "ERR_InjectedCtor")); + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/DeclaredIBindingsAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/DeclaredIBindingsAnalyzer.java new file mode 100644 index 000000000000..009aa6413088 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/DeclaredIBindingsAnalyzer.java @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.type; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractInterceptedElementAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ClassModelAnalyzer.ClassAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class DeclaredIBindingsAnalyzer extends + AbstractInterceptedElementAnalyzer implements ClassAnalyzer +{ + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ClassModelAnalyzer.ClassAnalyzer#analyze(javax.lang.model.element.TypeElement, javax.lang.model.element.TypeElement, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.util.List, org.netbeans.api.java.source.CompilationInfo, java.util.concurrent.atomic.AtomicBoolean) + */ + @Override + public void analyze( TypeElement element, TypeElement parent, + WebBeansModel model, AtomicBoolean cancel, + Result result ) + { + Set interceptorBindings = getInterceptorBindings(element, + model); + Map iBindings = new HashMap(); + if ( !interceptorBindings.isEmpty() ){ + result.requireCdiEnabled(element, model); + } + for (AnnotationMirror annotationMirror : interceptorBindings) { + Element iBinding = annotationMirror.getAnnotationType().asElement(); + AnnotationMirror found = iBindings.get( iBinding ); + if ( found != null && !isSame( found, annotationMirror , + model.getCompilationController())) + { + result.addError( element, model, + NbBundle.getMessage(DeclaredIBindingsAnalyzer.class, + "ERR_InvalidDuplicateIBindings", // NOI18N + ((TypeElement)iBinding).getQualifiedName().toString())); + break; + } + else { + iBindings.put(iBinding, annotationMirror ); + } + } + } + + private boolean isSame( AnnotationMirror first, + AnnotationMirror second , CompilationController controller ) + { + Element firstElement = first.getAnnotationType().asElement(); + Element secondElement = second.getAnnotationType().asElement(); + if ( !firstElement.equals(secondElement)){ + return false; + } + Map firstValues = first.getElementValues(); + Map secondValues = second.getElementValues(); + if ( firstValues.size() != secondValues.size() ){ + return false; + } + for (Entry entry : + firstValues.entrySet()) + { + AnnotationValue secondValue = secondValues.get(entry.getKey()); + AnnotationValue firstValue = entry.getValue(); + if ( !isSame( firstValue, secondValue, controller )){ + return false; + } + } + return true; + } + + private boolean isSame( AnnotationValue first, + AnnotationValue second , CompilationController controller) + { + Object firstValue = first.getValue(); + Object secondValue = second.getValue(); + if ( firstValue == null ){ + return secondValue == null; + } + if ( firstValue instanceof TypeMirror ){ + TypeMirror firstMirror = (TypeMirror)firstValue; + if ( secondValue instanceof TypeMirror ){ + return controller.getTypes().isSameType(firstMirror, + (TypeMirror)secondValue ); + } + else { + return false; + } + } + else if ( firstValue instanceof AnnotationMirror ){ + if ( secondValue instanceof AnnotationMirror ){ + return isSame((AnnotationMirror)firstValue, (AnnotationMirror)second, + controller); + } + else { + return false; + } + } + else if ( firstValue instanceof List){ + if ( secondValue instanceof List){ + List firstList = (List)firstValue; + List secondList = (List) secondValue; + if ( firstList.size() != secondList.size() ){ + return false; + } + for (int i =0; i handle = ElementHandle.create(element); + if ( helper != null ){ + helper.addInterceptedBean( result , + handle.resolve( result.getInfo())); + } + } + + + Set modifiers = element.getModifiers(); + boolean isFinal = modifiers.contains(Modifier.FINAL); + List methods = ElementFilter.methodsIn( + element.getEnclosedElements()); + ExecutableElement badMethod = null; + for (ExecutableElement method : methods) { + if ( cancel.get() ){ + return; + } + modifiers = method.getModifiers(); + if ( !modifiers.contains( Modifier.FINAL )){ + continue; + } + if ( modifiers.contains( Modifier.STATIC ) || + modifiers.contains( Modifier.PRIVATE)) + { + continue; + } + badMethod = method; + break; + } + if ( badMethod == null && !isFinal ){ + return; + } + if ( cancel.get() ){ + return; + } + if (hasIBindings && isFinal) { + result.addError(element, model, + NbBundle.getMessage( + InterceptedBeanAnalyzer.class, + "ERR_FinalInterceptedBean")); // NOI18N + } + if (hasIBindings && badMethod != null) { + result.addError(element, model, + NbBundle.getMessage( + InterceptedBeanAnalyzer.class, + "ERR_InterceptedBeanHasFinalMethod", badMethod + .getSimpleName().toString())); // NOI18N + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/ManagedBeansAnalizer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/ManagedBeansAnalizer.java new file mode 100644 index 000000000000..4724b014774d --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/ManagedBeansAnalizer.java @@ -0,0 +1,173 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.type; + +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; + +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ClassModelAnalyzer.ClassAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.hints.EditorAnnotationsHelper; +import org.netbeans.spi.editor.hints.Severity; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class ManagedBeansAnalizer implements ClassAnalyzer { + + private static final String EXTENSION = "jakarta.enterprise.inject.spi.Extension"; //NOI18N + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ClassModelAnalyzer.ClassAnalyzer#analyze(javax.lang.model.element.TypeElement, javax.lang.model.element.TypeElement, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.util.List, org.netbeans.api.java.source.CompilationInfo, java.util.concurrent.atomic.AtomicBoolean) + */ + @Override + public void analyze( TypeElement element, TypeElement parent, + WebBeansModel model, AtomicBoolean cancel, + Result result ) + { + boolean cdiManaged = model.getQualifiers( element, true ).size()>0; + if ( !cdiManaged ){ + return; + } + result.requireCdiEnabled(element, model); + if (cancel.get()) { + return; + } + checkCtor(element, model, result ); + if (cancel.get()) { + return; + } + checkInner(element, parent, model, result); + if (cancel.get()) { + return; + } + checkAbstract(element, model, result); + if (cancel.get()) { + return; + } + checkImplementsExtension(element, model, result); + if (cancel.get()) { + return; + } + checkDecorators( element , model , result ); + } + + private void checkDecorators( TypeElement element, WebBeansModel model, + Result result ) + { + Collection decorators = model.getDecorators(element); + if ( decorators!= null && decorators.size() >0 ){ + EditorAnnotationsHelper helper = EditorAnnotationsHelper.getInstance(result); + ElementHandle handle = ElementHandle.create(element); + if ( helper != null ){ + helper.addDecoratedBean( result , handle.resolve( result.getInfo() )); + } + } + } + + private void checkImplementsExtension( TypeElement element, + WebBeansModel model, Result result ) + { + TypeElement extension = model.getCompilationController().getElements(). + getTypeElement(EXTENSION); + if ( extension == null ){ + return; + } + TypeMirror elementType = element.asType(); + if ( model.getCompilationController().getTypes().isSubtype( + elementType, extension.asType())){ + result.addNotification(Severity.WARNING, element, + model, NbBundle.getMessage( ManagedBeansAnalizer.class, + "WARN_QualifiedElementExtension")); // NOI18N + } + } + + private void checkAbstract( TypeElement element, + WebBeansModel model, Result result ) + { + Set modifiers = element.getModifiers(); + if ( modifiers.contains( Modifier.ABSTRACT )){ + if ( AnnotationUtil.hasAnnotation(element, + AnnotationUtil.DECORATOR, model.getCompilationController()) ){ + return; + } + + // element is abstract and has no Decorator annotation + result.addNotification( Severity.WARNING, element, model, + NbBundle.getMessage(ManagedBeansAnalizer.class, + "WARN_QualifierAbstractClass")); // NOI18N + } + } + + private void checkInner( TypeElement element, TypeElement parent, + WebBeansModel model, Result result ) + { + if ( parent == null ){ + return; + } + Set modifiers = element.getModifiers(); + if ( !modifiers.contains( Modifier.STATIC )){ + result.addError(element, model, + NbBundle.getMessage(ManagedBeansAnalizer.class, + "ERR_NonStaticInnerType")); // NOI18N + } + } + + private void checkCtor( TypeElement element, WebBeansModel model, + Result result ) + { + List ctors = ElementFilter.constructorsIn( + element.getEnclosedElements()); + for (ExecutableElement ctor : ctors) { + Set modifiers = ctor.getModifiers(); + if ( modifiers.contains( Modifier.PRIVATE )){ + continue; + } + List parameters = ctor.getParameters(); + if ( parameters.size() ==0 ){ + return; + } + if ( AnnotationUtil.hasAnnotation(ctor, AnnotationUtil.INJECT_FQN, + model.getCompilationController())) + { + return; + } + } + // there is no non-private ctors without params or annotated with @Inject + result.addNotification( Severity.WARNING, element, model, + NbBundle.getMessage(ManagedBeansAnalizer.class, + "WARN_QualifierNoCtorClass")); // NOI18N + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/NamedModelAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/NamedModelAnalyzer.java new file mode 100644 index 000000000000..81503316f9d0 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/NamedModelAnalyzer.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.type; + +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ClassModelAnalyzer.ClassAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class NamedModelAnalyzer implements ClassAnalyzer { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ClassModelAnalyzer.ClassAnalyzer#analyze(javax.lang.model.element.TypeElement, javax.lang.model.element.TypeElement, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.util.List, org.netbeans.api.java.source.CompilationInfo, java.util.concurrent.atomic.AtomicBoolean) + */ + @Override + public void analyze( TypeElement element, TypeElement parent, + WebBeansModel model, AtomicBoolean cancel, + Result result ) + { + if ( !AnnotationUtil.hasAnnotation(element, AnnotationUtil.SPECIALIZES, + model.getCompilationController())) + { + return; + } + result.requireCdiEnabled(element, model); + if ( !AnnotationUtil.hasAnnotation(element, AnnotationUtil.NAMED, + model.getCompilationController())) + { + return; + } + TypeMirror superclass = element.getSuperclass(); + Element superElement = model.getCompilationController().getTypes(). + asElement( superclass ); + if ( cancel.get() ){ + return; + } + String name = model.getName(superElement); + if ( name == null ){ + return; + } + result.addError( element, model, NbBundle.getMessage( + NamedModelAnalyzer.class, "ERR_NamedSpecializes")); // NOI18N + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/ScopedBeanAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/ScopedBeanAnalyzer.java new file mode 100644 index 000000000000..45ffa366548a --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/ScopedBeanAnalyzer.java @@ -0,0 +1,225 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.type; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; + +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractScopedAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ClassModelAnalyzer.ClassAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.spi.editor.hints.Severity; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class ScopedBeanAnalyzer extends AbstractScopedAnalyzer + implements ClassAnalyzer +{ + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ClassModelAnalyzer.ClassAnalyzer#analyze(javax.lang.model.element.TypeElement, javax.lang.model.element.TypeElement, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.util.List, org.netbeans.api.java.source.CompilationInfo, java.util.concurrent.atomic.AtomicBoolean) + */ + @Override + public void analyze( TypeElement element, TypeElement parent, + WebBeansModel model, AtomicBoolean cancel, + Result result ) + { + analyzeScope(element, model, cancel , result ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractScopedAnalyzer#checkScope(javax.lang.model.element.TypeElement, javax.lang.model.element.Element, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.util.List, org.netbeans.api.java.source.CompilationInfo, java.util.concurrent.atomic.AtomicBoolean) + */ + @Override + protected void checkScope( TypeElement scopeElement, Element element, + WebBeansModel model, AtomicBoolean cancel , Result result ) + { + if ( cancel.get() ){ + return; + } + checkProxiability(scopeElement, element, model, result ); + if ( cancel.get() ){ + return; + } + checkPublicField(scopeElement , element , model , result ); + if ( cancel.get() ){ + return; + } + checkParameterizedBean(scopeElement , element , model , result ); + if ( cancel.get() ){ + return; + } + checkInterceptorDecorator( scopeElement , element , model , result); + if ( cancel.get() ){ + return; + } + checkPassivationCapable( scopeElement , element , model , result ); + } + + private void checkPassivationCapable( TypeElement scopeElement, + Element element, WebBeansModel model, Result result ) + { + if ( !isPassivatingScope(scopeElement, model) ){ + return; + } + if ( AnnotationUtil.isSessionBean(element, model.getCompilationController())){ + if ( AnnotationUtil.hasAnnotation(element, + AnnotationUtil.STATEFUL, model.getCompilationController())) + { + return; + } + else { + result.addError(element, model , + NbBundle.getMessage(ScopedBeanAnalyzer.class, + "ERR_NotPassivationSessionBean", // NOI18N + scopeElement.getQualifiedName().toString())); + return; + } + } + if ( !isSerializable(element, model) ){ + result.addError(element, model , + NbBundle.getMessage(ScopedBeanAnalyzer.class, + "ERR_NotPassivationManagedBean", // NOI18N + scopeElement.getQualifiedName().toString())); + } + // TODO : all interceptors ans decorators of bean should be also passivation capable + } + + private void checkInterceptorDecorator( TypeElement scopeElement, + Element element, WebBeansModel model, Result result ) + { + if ( scopeElement.getQualifiedName().contentEquals(AnnotationUtil.DEPENDENT)){ + return; + } + AnnotationMirror annotationMirror = AnnotationUtil.getAnnotationMirror( + element, model.getCompilationController(), + AnnotationUtil.INTERCEPTOR, AnnotationUtil.DECORATOR); + if ( annotationMirror!= null ){ + result.addNotification( Severity.WARNING, element, model, + NbBundle.getMessage(ScopedBeanAnalyzer.class, + "WARN_ScopedDecoratorInterceptor" )); // NOI18N + } + } + + private void checkParameterizedBean( TypeElement scopeElement, + Element element, WebBeansModel model, + Result result ) + { + if ( AnnotationUtil.DEPENDENT.contentEquals( + scopeElement.getQualifiedName())) + { + return; + } + result.requireCdiEnabled(element, model); + TypeMirror type = element.asType(); + if ( type instanceof DeclaredType ){ + List typeArguments = ((DeclaredType)type).getTypeArguments(); + if ( typeArguments.size() != 0 ){ + result.addError(element, model, + NbBundle.getMessage(ScopedBeanAnalyzer.class, + "ERR_IncorrectScopeForParameterizedBean" )); // NOI18N + } + } + } + + private void checkPublicField( TypeElement scopeElement, Element element, + WebBeansModel model, Result result ) + { + if ( AnnotationUtil.DEPENDENT.contentEquals( + scopeElement.getQualifiedName())) + { + return; + } + result.requireCdiEnabled(element, model); + List fields = ElementFilter.fieldsIn( + element.getEnclosedElements()); + for (VariableElement field : fields) { + Set modifiers = field.getModifiers(); + if ( modifiers.contains(Modifier.PUBLIC ) + && (!modifiers.contains(Modifier.STATIC) || !model.isCdi11OrLater())){ + result.addError(element, model , + NbBundle.getMessage(ScopedBeanAnalyzer.class, + "ERR_IcorrectScopeWithPublicField", + field.getSimpleName().toString())); + return; + } + } + } + + private void checkProxiability( TypeElement scopeElement, Element element, + WebBeansModel model, Result result ) + { + boolean isNormal = AnnotationUtil.hasAnnotation(scopeElement, + AnnotationUtil.NORMAL_SCOPE_FQN, model.getCompilationController()); + if ( isNormal ){ + result.requireCdiEnabled(element, model); + checkFinal( element , model, result ); + } + } + + private void checkFinal( Element element, WebBeansModel model, + Result result ) + { + if ( !( element instanceof TypeElement )){ + return; + } + Set modifiers = element.getModifiers(); + if ( modifiers.contains( Modifier.FINAL) ){ + result.addError( element, model, + NbBundle.getMessage(ScopedBeanAnalyzer.class, + "ERR_FinalScopedClass")); + return; + } + List methods = ElementFilter.methodsIn( + element.getEnclosedElements()); + for (ExecutableElement method : methods) { + modifiers = method.getModifiers(); + if (modifiers.contains(Modifier.FINAL)) { + result.addNotification( Severity.WARNING, method, model, + NbBundle.getMessage( + ScopedBeanAnalyzer.class, + "WARN_FinalScopedClassMethod")); + } + } + } + + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/SessionBeanAnalyzer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/SessionBeanAnalyzer.java new file mode 100644 index 000000000000..e13377f48e01 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/SessionBeanAnalyzer.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.type; + +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ClassModelAnalyzer.ClassAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result; +import org.netbeans.modules.jakarta.web.beans.api.model.CdiException; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class SessionBeanAnalyzer implements ClassAnalyzer { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ClassModelAnalyzer.ClassAnalyzer#analyze(javax.lang.model.element.TypeElement, javax.lang.model.element.TypeElement, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.util.List, org.netbeans.api.java.source.CompilationInfo, java.util.concurrent.atomic.AtomicBoolean) + */ + @Override + public void analyze( TypeElement element, TypeElement parent, + WebBeansModel model, AtomicBoolean cancel , + Result result ) + { + boolean isSingleton = AnnotationUtil.hasAnnotation(element, + AnnotationUtil.SINGLETON, model.getCompilationController()); + boolean isStateless = AnnotationUtil.hasAnnotation(element, + AnnotationUtil.STATELESS, model.getCompilationController()); + if ( cancel.get() ){ + return; + } + try { + String scope = model.getScope( element ); + if ( isSingleton ) { + if ( AnnotationUtil.APPLICATION_SCOPED.equals( scope ) || + AnnotationUtil.DEPENDENT.equals( scope ) ) + { + return; + } + result.requireCdiEnabled(element, model); + result.addError( element, model, + NbBundle.getMessage(SessionBeanAnalyzer.class, + "ERR_InvalidSingletonBeanScope")); // NOI18N + } + else if ( isStateless ) { + if ( !AnnotationUtil.DEPENDENT.equals( scope ) ) + { + result.addError( element, model, + NbBundle.getMessage(SessionBeanAnalyzer.class, + "ERR_InvalidStatelessBeanScope")); // NOI18N + } + } + } + catch (CdiException e) { + result.requireCdiEnabled(element, model); + informCdiException(e, element, model, result ); + } + } + + private void informCdiException(CdiException exception , Element element, + WebBeansModel model, Result result ) + { + result.addError(element, model, exception.getMessage()); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/TypedClassAnalizer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/TypedClassAnalizer.java new file mode 100644 index 000000000000..f25e404250ea --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/analysis/analyzer/type/TypedClassAnalizer.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis.analyzer.type; + +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractTypedAnalyzer; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ClassElementAnalyzer.ClassAnalyzer; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class TypedClassAnalizer extends AbstractTypedAnalyzer implements + ClassAnalyzer +{ + + @Override + public void analyze( TypeElement element, TypeElement parent, + AtomicBoolean cancel, CdiAnalysisResult result ) + { + analyze(element, element.asType() , cancel , result ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractTypedAnalyzer#addError(javax.lang.model.element.Element, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer.Result) + */ + @Override + protected void addError( Element element, CdiAnalysisResult result ) + { + result.addError( element, NbBundle.getMessage( + TypedClassAnalizer.class, "ERR_BadRestritedType")); // NOI18N + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AbstractTypedAnalyzer#checkSpecializes(javax.lang.model.element.Element, javax.lang.model.type.TypeMirror, java.util.List, java.util.concurrent.atomic.AtomicBoolean, org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ElementAnalyzer.Result) + */ + @Override + protected void checkSpecializes( Element element, TypeMirror elementType, + List restrictedTypes, AtomicBoolean cancel , CdiAnalysisResult result ) + { + TypeElement typeElement = (TypeElement)element; + TypeMirror superclass = typeElement.getSuperclass(); + Element superElement = result.getInfo().getTypes().asElement(superclass); + if ( !( superElement instanceof TypeElement )){ + return; + } + List restrictedSuper = getRestrictedTypes(superElement, + result.getInfo(), cancel); + if ( cancel.get()){ + return; + } + /* + * No need to look at the TypeMirrors here. The correctness of the + * bean types are guaranteed by inheritance hierarchy. + * TypeMirrors here couldn't be arrays or primitives. + * ( But it is possible for production elements where TypeMirrors shouldn't + * be checked only against corresponding TypeElement ). + */ + + Set specializedBeanTypes; + if ( restrictedSuper == null ){ + specializedBeanTypes = getUnrestrictedBeanTypes( + (TypeElement)superElement, result.getInfo()); + } + else { + specializedBeanTypes = getElements( restrictedSuper, result.getInfo()); + } + Set restrictedElements = getElements(restrictedTypes, + result.getInfo()); + restrictedElements.add( result.getInfo().getElements().getTypeElement( + Object.class.getCanonicalName())); + if ( !restrictedElements.containsAll(specializedBeanTypes)){ + result.addError( element, NbBundle.getMessage( + TypedClassAnalizer.class, "ERR_BadSpecializesBeanType")); // NOI18N + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/AbstractModelImplementation.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/AbstractModelImplementation.java new file mode 100644 index 000000000000..41a6ea2efa0b --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/AbstractModelImplementation.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.api.model; + +import java.util.Collection; + +import org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider; +import org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProviderFactory; +import org.openide.util.Lookup; + + +/** + * @author ads + * + */ +public abstract class AbstractModelImplementation { + + protected AbstractModelImplementation( ModelUnit unit ){ + myUnit = unit; + myModel = new WebBeansModel( this ); + Collection factories = + Lookup.getDefault().lookupAll( + WebBeansModelProviderFactory.class); + for( WebBeansModelProviderFactory factory : factories ){ + myProvider = factory.createWebBeansModelProvider(this); + if ( myProvider != null ){ + break; + } + } + + } + + public ModelUnit getModelUnit(){ + return myUnit; + } + + public BeansModel getBeansModel(){ + return BeansModelFactory.getModel(getModelUnit()); + } + + protected WebBeansModel getModel(){ + return myModel; + } + + protected WebBeansModelProvider getProvider(){ + return myProvider; + } + + private ModelUnit myUnit; + private WebBeansModel myModel; + private WebBeansModelProvider myProvider; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/BeanArchiveType.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/BeanArchiveType.java new file mode 100644 index 000000000000..e77dfb73cf15 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/BeanArchiveType.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.api.model; + +/** + * Defines whether the given project (model) internally work with implicit or explicite bean archive. + * @author Martin Fousek + */ +public enum BeanArchiveType { + NONE,//not an archive + IMPLICIT,//annotated + EXPLICIT;//all +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/BeansModel.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/BeansModel.java new file mode 100644 index 000000000000..791e76392b7b --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/BeansModel.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.api.model; + +import java.util.LinkedHashSet; +import java.util.Set; + + +/** + * Merged model for beans.xml files. + * @author ads + * + */ +public interface BeansModel { + + /** + * @return all interceptor classes FQNs found in beans.xml files + */ + LinkedHashSet getInterceptorClasses(); + + /** + * @return all decorator classes FQNs found in beans.xml files + */ + LinkedHashSet getDecoratorClasses(); + + /** + * @return all alternative classes FQNs found in beans.xml files + */ + Set getAlternativeClasses(); + + /** + * @return all alternative stereotypes FQNs found in beans.xml files + */ + Set getAlternativeStereotypes(); + + /** + * Gets information about the Bean Archive type of the project. + * Introduced by CDI 1.1 with implicit bean archive. + * @return bean archive type, never {@code null} + */ + BeanArchiveType getBeanArchiveType(); + + boolean isCdi11OrLater(); + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/BeansModelFactory.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/BeansModelFactory.java new file mode 100644 index 000000000000..9d2a1a80b355 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/BeansModelFactory.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.api.model; + +import java.util.Map; +import java.util.WeakHashMap; + +import org.netbeans.modules.jakarta.web.beans.impl.model.BeansModelImpl; + + +/** + * @author ads + * + */ +public final class BeansModelFactory { + + private BeansModelFactory(){ + } + + public static BeansModel createModel( ModelUnit unit ){ + return new BeansModelImpl(unit); + } + + public static synchronized BeansModel getModel( ModelUnit unit ){ + BeansModel model = MODELS.get( unit ); + if ( model == null ){ + model = createModel( unit ); + MODELS.put(unit, model); + } + return model; + } + + private static final Map MODELS = + new WeakHashMap(); +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/BeansResult.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/BeansResult.java new file mode 100644 index 000000000000..9a1c0df9706a --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/BeansResult.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.api.model; + +import javax.lang.model.element.Element; + + +/** + * Common interface for result that contains elements which + * can be enabled/disabled via beans.xml file. + * + * @author ads + * + */ +public interface BeansResult { + + boolean isDisabled( Element element ); + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/CdiException.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/CdiException.java new file mode 100644 index 000000000000..ca5b1812ad9e --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/CdiException.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.api.model; + + +/** + * @author ads + * + */ +public class CdiException extends Exception { + + private static final long serialVersionUID = 8768805477182583488L; + + public CdiException( String message ){ + super( message ); + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/DependencyInjectionResult.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/DependencyInjectionResult.java new file mode 100644 index 000000000000..0e29d76d363f --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/DependencyInjectionResult.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.api.model; + +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; + + +/** + * Represent eligible for injection element search result. + * + * @author ads + * + */ +public interface DependencyInjectionResult { + + enum ResultKind { + /** + * This kind correspond to Error result only + */ + DEFINITION_ERROR, + /** + * This kind represents at least InjectableResult and ResolutionResult. + * Also there could be additional hints with set of eligible for injection + * elements ( which are disabled , turned off alternatives, .... ) + * represented by ApplicableResult. + */ + INJECTABLE_RESOLVED, + /** + * - No eligible for injection element found at all + * - Only disabled beans are found + * - Ambiguous dependencies result + * It could be represented by Error only ( nothing found + * at all ) or Error, ResolutionResult and ApplicableResult with + * information about probable eligible for injection elements. + */ + RESOLUTION_ERROR, + /** + * This kind is like INJECTABLE_RESOLVED but it can contain + * several eligible for injection elements from very beginning. + * It is used when multiple eligible for injection elements are + * valid result. F.e. it is normal to find a number elements + * via programmatic lookup . + * It is represented at least by ApplicableResult and ResolutionResult. + */ + INJECTABLES_RESOLVED, + } + + /** + * @return element injection point which is used for injectable search + */ + VariableElement getVariable(); + + TypeMirror getVariableType(); + + ResultKind getKind(); + + interface Error extends DependencyInjectionResult { + + String getMessage(); + } + + interface ResolutionResult extends DependencyInjectionResult, Result { + + /** + * Check whether element is alternative. + * element could be eligible for injection element + * ( which is found as result here ) or stereotype. + * @param element checked element + * @return true if element is alternative + */ + boolean isAlternative( Element element ); + + boolean hasAlternative( Element element ); + } + + interface InjectableResult extends DependencyInjectionResult { + /** + * null is returned if there is no eligible element for injection + * ( no element which could be a pretender). + * + * it could be a result of unsatisfied or ambiguous dependency. + * F.e. unsatisfied dependency : there is a pretender satisfy typesafe + * resolution but something incorrect ( parameterized type is not valid , etc. ). + * Ambiguous dependency : there are a number of appropriate elements. + * + * + * @return element ( type definition, production field/method) + * that is used in injected point identified by {@link #getVariable()} + */ + Element getElement(); + } + + interface ApplicableResult extends DependencyInjectionResult, BeansResult { + public Set getTypeElements(); + + public Set getProductions(); + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/InjectionPointDefinitionError.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/InjectionPointDefinitionError.java new file mode 100644 index 000000000000..aca0bda1be35 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/InjectionPointDefinitionError.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.api.model; + +import javax.lang.model.element.Element; + + +/** + * This exception could be thrown when injection point deifinition + * contains error. + * @author ads + * + */ +public class InjectionPointDefinitionError extends CdiException { + + private static final long serialVersionUID = -6893993336079352757L; + + public InjectionPointDefinitionError(Element errorElement, String msg) { + super( msg ); + myElement = errorElement; + } + + /** + * There could be errors detected when element is checked as injection point. + * In most such cases possible injection point is the error element. + * But in some cases error could be detected on enclosing element. + * F.e. method could be wrongly defined . In this case its parameters + * cannot be considered as correct injection points. + * + * @return element that is wrongly defined + */ + public Element getErrorElement(){ + return myElement; + } + + private Element myElement; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/InterceptorsResult.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/InterceptorsResult.java new file mode 100644 index 000000000000..76eecb47d7bf --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/InterceptorsResult.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.api.model; + +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + + +/** + * @author ads + * + */ +public interface InterceptorsResult extends Result, BeansResult { + + /** + * Subject element accessor . + * @return element which is used for interceptor resolution + */ + Element getElement(); + + /** + * Returns interceptors which have @Interceptor annotation and + * meets the interceptor resolution requirements. + * @return result of interceptor resolution. + */ + List getResolvedInterceptors(); + + /** + * Interceptors could be assigned via @Interceptors annotation. + * @return explicitly declared interceptors + */ + List getDeclaredInterceptors(); + + /** + * The result is union of resolved and declared interceptors. + * @return all available interceptors + */ + List getAllInterceptors(); + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/ModelUnit.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/ModelUnit.java new file mode 100644 index 000000000000..4a7b9d205683 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/ModelUnit.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.api.model; + +import java.net.URISyntaxException; + +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.java.source.ClasspathInfo; +import org.netbeans.api.project.Project; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +public class ModelUnit { + + private ModelUnit( ClassPath bootPath, ClassPath compilePath, + ClassPath sourcePath, Project project) + { + myBootPath= bootPath; + myCompilePath = compilePath; + mySourcePath = sourcePath; + myProject = project; + myClassPathInfo = ClasspathInfo.create(bootPath, + compilePath, sourcePath); + } + + public ClassPath getBootPath() { + return myBootPath; + } + + public ClassPath getCompilePath() { + return myCompilePath; + } + + public ClassPath getSourcePath() { + return mySourcePath; + } + + public Project getProject() { + return myProject; + } + + @Override + public int hashCode() { + return 37*(37*myBootPath.hashCode() + myCompilePath.hashCode()) + +mySourcePath.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ModelUnit) { + ModelUnit unit = (ModelUnit) obj; + return myBootPath.equals( unit.myBootPath ) && myCompilePath.equals( + unit.myCompilePath ) && mySourcePath.equals( mySourcePath ); + } + else { + return false; + } + } + + public static ModelUnit create(ClassPath bootPath, ClassPath compilePath, + ClassPath sourcePath, Project project) + { + return new ModelUnit(bootPath, compilePath, sourcePath, project); + } + + public ClasspathInfo getClassPathInfo(){ + return myClassPathInfo; + } + + private static boolean equals(ClassPath cp1, ClassPath cp2) { + if (cp1.entries().size() != cp2.entries().size()) { + return false; + } + for (int i = 0; i < cp1.entries().size(); i++) { + try { + if (!cp1.entries().get(i).getURL().toURI() + .equals(cp2.entries().get(i).getURL().toURI())) + { + return false; + } + } + catch (URISyntaxException e) { + if ( !cp1.entries().get(i).equals(cp2.entries().get(i)) ){ + return false; + } + } + } + return true; + } + + private static int computeClassPathHash(ClassPath classPath) { + int hashCode = 0; + for (ClassPath.Entry entry : classPath.entries()) { + hashCode = 37*hashCode + entry.getURL().getPath().hashCode(); + } + return hashCode; + } + + FileObject getSourceFileObject(){ + FileObject[] roots = mySourcePath.getRoots(); + if ( roots!= null && roots.length >0 ){ + return roots[0]; + } + return null; + } + + private final ClasspathInfo myClassPathInfo; + private final ClassPath myBootPath; + private final ClassPath myCompilePath; + private final ClassPath mySourcePath; + private final Project myProject; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/Result.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/Result.java new file mode 100644 index 000000000000..a4021a5d2de6 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/Result.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.api.model; + +import java.util.List; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; + + +/** + * Common interface for results that contains elements with stereotypes. + * + * @author ads + * + */ +public interface Result { + + /** + * Return list of all element's stereotypes ( including recursively + * inherited ). + * @param element element with stereotypes + * @return list of element's stereotypes + */ + List getAllStereotypes( Element element ); + + List getStereotypes( Element element ); + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/WebBeansModel.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/WebBeansModel.java new file mode 100644 index 000000000000..bec135996eaf --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/WebBeansModel.java @@ -0,0 +1,303 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.api.model; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.modules.jakarta.web.beans.impl.model.WebBeansModelProviderImpl; +import org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider; + + +/** + * @author ads + * + */ +public final class WebBeansModel { + + WebBeansModel( AbstractModelImplementation impl ){ + myImpl = impl; + } + + /** + * Find injectable elements that could be used for given injection point. + * + * parentType parameter could be a null . In this case + * type definition which contains element is used as parentType. + * This parameter is needed when element is defined in + * superclass and this superclass is generic. In this case element + * type ( TypeMirror ) could vary respectively subclass definition ( it could uses + * real class in generic type parameter ). Type of element in this case + * is not just element.asType(). It is + * CompilationInfo.getTypes().asMemberOf(parentType,element). + * This is significant difference. + * + * Return value depends on injection point type. + * Injection point could be defined via + * programmatic lookup which is dynamically specify injectable type. + * Such situation appears when injection point uses Instance interface. + * In case of @Any binding usage this list will contain all + * possible binding types for element ( all beans + * that implements or extends type parameter for Instance<> ). + * + * See parentType parameter explanation in + * {@link #lookupInjectables(VariableElement, DeclaredType)}. + * + * @param element injection point + * @param parentType parent type of element + * @return search result information + */ + public DependencyInjectionResult lookupInjectables( VariableElement element , + DeclaredType parentType, AtomicBoolean cancel) + { + return getProvider().lookupInjectables(element, parentType, cancel); + } + + /** + * Test if variable element is injection point. + *
 
+     * Two cases possible here:
+     * - element has @Inject annotation
+     * - element is parameter of method which is annotated with @Inject 
+     * 
+ * + * @param element element for check + * @return true if element is simple injection point + * @throws WebBeansModelException if element could be injection + * point but something wrong ( f.e. it has bindings and has no @Produces + * annotation bit it is initialized ). + * @throws InjectionPointDefinitionError if element definition contains error + */ + public boolean isInjectionPoint( VariableElement element ) + throws InjectionPointDefinitionError + { + return getProvider().isInjectionPoint(element); + } + + /** + * Test if variable element is event injection point. + * + * @param element element for check + * @return true if element is event injection point + */ + public boolean isEventInjectionPoint( VariableElement element ) + { + TypeMirror elementType = element.asType(); + Element typeElement = getCompilationController(). + getTypes().asElement( elementType); + if ( typeElement instanceof TypeElement ){ + String typeElementFqn = ((TypeElement)typeElement).getQualifiedName(). + toString(); + if ( WebBeansModelProviderImpl.EVENT_INTERFACE.equals( typeElementFqn )){ + try { + return isInjectionPoint(element); + } + catch(InjectionPointDefinitionError e ){ + return false; + } + } + } + return false; + } + + /** + * Test if variable element is injection point that is used for + * programmatic lookup. It could happen if variable declared via + * Instance interface with qualifier annotations. + * Typesafe resolution in this case could not be done + * statically and method + * {@link #lookupInjectables1(VariableElement, DeclaredType)} should + * be used to access to possible bean types. + * @param element element for check + * @return true if element is dynamic injection point + */ + public boolean isDynamicInjectionPoint( VariableElement element ) { + return getProvider().isDynamicInjectionPoint(element); + } + + /** + * Access to @Named elements. Method {@link #getName(Element)} + * should be used for getting name of element. + * @return list of elements annotated with @Named + */ + public List getNamedElements(){ + return getProvider().getNamedElements( new AtomicBoolean(false) ); + } + + public boolean isCdi11OrLater() { + return getProvider().isCdi11OrLater(); + } + + /** + * Returns name of element if it annotated with @Named. + * Otherwise returns null. + * @param element @Named element + * @return name of element + */ + public String getName( Element element ){ + return getProvider().getName( element); + } + + /** + * This method is used for resolve name to Java model type. + * One can resolve enclosed elements ( fields , methods ,.... ) + * via Java model API and reference which method returns. + * @param fqn fully qualified name of type + * @return type with given FQN fqn + */ + public TypeMirror resolveType(String fqn){ + return getProvider().resolveType(fqn); + } + + public CompilationController getCompilationController(){ + return getProvider().getCompilationController(); + } + + /** + * Returns all qualifiers for element. + * element could be variable ( injection point , producer field ), + * type element ( bean type with binding ) and production method. + * @param element element with qualifiers + * @param all if true all annotations ( including inherited by @Specializes ) will be returned + * @return list of all bindings for element + */ + public List getQualifiers( Element element , boolean all){ + return getProvider().getQualifiers( element , all ); + } + + /** + * If element has no declared qualifiers or just @Named + * qualifier then it has implicit @Default qualifier. + * + * @param element element with qualifiers + * @return true if element has @Default qualifier which is not declared explicitly + */ + public boolean hasImplicitDefaultQualifier( Element element ){ + return getProvider().hasImplicitDefaultQualifier( element ); + } + + /** + * Returns all observer methods for given injection point element + * field. + * + * @param element event injection point + * @param parentType parent type of element + * @return list of observer methods that will be notified about event fired by element + */ + public List getObservers(VariableElement element , + DeclaredType parentType) + { + return getProvider().getObservers( element , parentType); + } + + /** + * Returns all event injection points that notifies observer method + * element on event fire. + * + * @param element observer method + * @param parentType parent type of element + * @return list of event injection points that are used for firing event + */ + public List getEventInjectionPoints( ExecutableElement element, + DeclaredType parentType ) + { + return getProvider().getEventInjectionPoints( element , parentType); + } + + /** + * Returns parameter of method element annotated by @Observes. + * Null will be returned if method is not observer method. + * + * @param element observer method + * @param parentType parent type of element + * @return observer parameter + */ + public VariableElement getObserverParameter(ExecutableElement element ) + { + return getProvider().getObserverParameter( element ); + } + + /** + * Returns Scope FQN for the specified element. + * @param element element which scope needs to be got + * @return scope of the element + */ + public String getScope( Element element ) throws CdiException{ + return getProvider().getScope( element ); + } + + /** + * Returns decorators for given type element. + * Decorator resolution is described in the 8.3 section of JSR-299 spec: + * - element bean should be assignable to the @Delegate injection point according special rules + * - decorator should be also enabled in the beans.xml + * The latter condition is not checked here. One should ask the + * BeansModel ( it is accessed via AbstractModelImplementation ) for + * enabled decorators. + * @param element decorated element + * @return collection of matched decorators + */ + public Collection getDecorators( TypeElement element ){ + return getProvider().getDecorators( element ); + } + + /** + * Lookup interceptors ( classes annotated with @Interceptor ) which + * are resolved for element. + * The element could be Class definition ( TypeElment ) + * or method ( ExecutableElement ). + * Interceptors could be applied to the methods only but class + * could also have interceptor bindings so this method could be + * useful for classes also. + * @param element type element or method element + * @return found interceptors + */ + public InterceptorsResult getInterceptors( Element element ){ + return getProvider().getInterceptors( element ); + } + + /** + * Returns interceptor bindings declared for element. + * @param element element annotated with interceptor bindings + * @return interceptor bindings + */ + public Collection getInterceptorBindings( Element element ){ + return getProvider().getInterceptorBindings(element); + } + + public AbstractModelImplementation getModelImplementation(){ + return myImpl; + } + + private WebBeansModelProvider getProvider(){ + return getModelImplementation().getProvider(); + } + + private AbstractModelImplementation myImpl; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/WebBeansModelFactory.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/WebBeansModelFactory.java new file mode 100644 index 000000000000..b561c1bf7cc7 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/api/model/WebBeansModelFactory.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.api.model; + +import java.lang.ref.WeakReference; +import java.util.HashMap; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.spi.MetadataModelFactory; +import org.netbeans.modules.jakarta.web.beans.impl.model.WebBeansModelImplementation; + + +/** + * @author ads + * + */ +public final class WebBeansModelFactory { + + private WebBeansModelFactory(){ + } + + public static synchronized MetadataModel getMetaModel( ModelUnit unit ){ + WeakReference> reference = MODELS.get( unit ); + MetadataModel metadataModel = null; + if ( reference != null ){ + metadataModel = reference.get(); + } + if ( metadataModel == null ){ + metadataModel = createMetaModel(unit); + if ( reference == null ){ + reference = new WeakReference>( metadataModel); + } + MODELS.put( unit, reference ); + } + return metadataModel; + } + + public static MetadataModel createMetaModel( ModelUnit unit ){ + return MetadataModelFactory.createMetadataModel( + WebBeansModelImplementation.createMetaModel(unit )); + } + + private static HashMap>> + MODELS = new HashMap>>(); +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/BeansCompletionItem.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/BeansCompletionItem.java new file mode 100644 index 000000000000..13cd25a83242 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/BeansCompletionItem.java @@ -0,0 +1,366 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.completion; + +import org.netbeans.api.editor.completion.Completion; +import org.netbeans.editor.BaseDocument; +import org.netbeans.spi.editor.completion.*; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.event.KeyEvent; +import javax.swing.ImageIcon; +import javax.swing.text.BadLocationException; +import javax.swing.text.JTextComponent; +import javax.swing.text.Position; +import org.netbeans.spi.editor.completion.support.CompletionUtilities; + +/** + * + * @author Dusan Balek, Andrei Badea, Marek Fukala + */ +public abstract class BeansCompletionItem implements CompletionItem { + + static BeansCompletionItem createBeansTagValueItem(int substitutionOffset, String fullName, String simpleName) { + return new TagClassValueItem(substitutionOffset, fullName, simpleName); + } + protected int substituteOffset = -1; + + public abstract String getItemText(); + + public String getSubstitutionText() { + return getItemText(); + } + + public int getSubstituteOffset() { + return substituteOffset; + } + + public boolean substituteCommonText(JTextComponent c, int offset, int len, int subLen) { + // [PENDING] not enough info in parameters... + // commonText + // substituteExp + return false; + } + + public boolean substituteText(JTextComponent c, int offset, int len, boolean shifted) { + BaseDocument doc = (BaseDocument) c.getDocument(); + String text = getSubstitutionText(); + + if (text != null) { + if (toAdd != null && !toAdd.equals("\n")) // NOI18N + { + text += toAdd; + } + // Update the text + doc.atomicLock(); + try { + String textToReplace = doc.getText(offset, len); + if (text.equals(textToReplace)) { + return false; + } + + if(!shifted) {//we are not in part of literal completion + //dirty hack for @Table(name=CUS| + if (!text.startsWith("\"")) { + text = quoteText(text); + } + + //check if there is already an end quote + char ch = doc.getText(offset + len, 1).charAt(0); + if (ch == '"') { + //remove also this end quote since the inserted value is always quoted + len++; + } + } + + doc.remove(offset, len); + doc.insertString(offset, text, null); + } catch (BadLocationException e) { + // Can't update + } finally { + doc.atomicUnlock(); + } + return true; + + } else { + return false; + } + } + + public boolean canFilter() { + return true; + } + + public boolean cutomPosition() { + return false; + } + + public int getCutomPosition() { + return -1; + } + + public Component getPaintComponent(javax.swing.JList list, boolean isSelected, boolean cellHasFocus) { + Component ret = getPaintComponent(isSelected); + if (ret == null) { + return null; + } + if (isSelected) { + ret.setBackground(list.getSelectionBackground()); + ret.setForeground(list.getSelectionForeground()); + } else { + ret.setBackground(list.getBackground()); + ret.setForeground(list.getForeground()); + } + ret.getAccessibleContext().setAccessibleName(getItemText()); + ret.getAccessibleContext().setAccessibleDescription(getItemText()); + return ret; + } + + public abstract Component getPaintComponent(boolean isSelected); + + @Override + public int getPreferredWidth(Graphics g, Font defaultFont) { + Component renderComponent = getPaintComponent(false); + return renderComponent.getPreferredSize().width; + } + + @Override + public String toString() { + return getItemText(); + } + // CompletionItem implementation + public static final String COMPLETION_SUBSTITUTE_TEXT = "completion-substitute-text"; //NOI18N + static String toAdd; + + @Override + public void processKeyEvent(KeyEvent evt) { + if (evt.getID() == KeyEvent.KEY_TYPED) { + Completion completion = Completion.get(); + switch (evt.getKeyChar()) { + case ' ': + if (evt.getModifiers() == 0) { + completion.hideCompletion(); + completion.hideDocumentation(); + } + break; + } + } + } + + protected String quoteText(String s) { + return "\"" + s + "\""; + } + + @Override + public CharSequence getSortText() { + return getItemText(); + } + + @Override + public CharSequence getInsertPrefix() { + return getItemText(); + } + + @Override + public CompletionTask createDocumentationTask() { + return null; + } + + @Override + public CompletionTask createToolTipTask() { + return null; + } + + @Override + public boolean instantSubstitution(JTextComponent c) { + Completion completion = Completion.get(); + completion.hideCompletion(); + completion.hideDocumentation(); + defaultAction(c); + return true; + } + + @Override + public void defaultAction(JTextComponent component) { + Completion completion = Completion.get(); + completion.hideCompletion(); + completion.hideDocumentation(); + defaultAction(component, ""); + } + + private boolean defaultAction(JTextComponent component, String addText) { + int substOffset = substituteOffset; + if (substOffset == -1) { + substOffset = component.getCaret().getDot(); + } + BeansCompletionItem.toAdd = addText; + return substituteText(component, substOffset, component.getCaret().getDot() - substOffset, false); + } + + private abstract static class BeansXmlCompletionItem extends BeansCompletionItem { + ///////// + + protected int substitutionOffset; + + protected BeansXmlCompletionItem(int substitutionOffset) { + this.substitutionOffset = substitutionOffset; + } + + @Override + public void defaultAction(JTextComponent component) { + if (component != null) { + Completion.get().hideDocumentation(); + Completion.get().hideCompletion(); + int caretOffset = component.getSelectionEnd(); + substituteText(component, substitutionOffset, caretOffset - substitutionOffset, null); + } + } + + protected void substituteText(JTextComponent c, int offset, int len, String toAdd) { + BaseDocument doc = (BaseDocument) c.getDocument(); + CharSequence prefix = getInsertPrefix(); + String text = prefix.toString(); + if (toAdd != null) { + text += toAdd; + } + + doc.atomicLock(); + try { + Position position = doc.createPosition(offset); + doc.remove(offset, len); + doc.insertString(position.getOffset(), text.toString(), null); + } catch (BadLocationException ble) { + // nothing can be done to update + } finally { + doc.atomicUnlock(); + } + } + + @Override + public String getSubstitutionText() { + return getInsertPrefix().toString(); + } + + @Override + public void processKeyEvent(KeyEvent evt) { + } + + @Override + public int getPreferredWidth(Graphics g, Font defaultFont) { + return CompletionUtilities.getPreferredWidth(getLeftHtmlText(), + getRightHtmlText(), g, defaultFont); + } + + @Override + public void render(Graphics g, Font defaultFont, Color defaultColor, + Color backgroundColor, int width, int height, boolean selected) { + CompletionUtilities.renderHtml(getIcon(), getLeftHtmlText(), + getRightHtmlText(), g, defaultFont, defaultColor, width, height, selected); + } + + @Override + public CompletionTask createDocumentationTask() { + return null; + } + + @Override + public CompletionTask createToolTipTask() { + return null; + } + + @Override + public boolean instantSubstitution(JTextComponent component) { + defaultAction(component); + return true; + } + + protected String getLeftHtmlText() { + return null; + } + + protected String getRightHtmlText() { + return null; + } + + protected ImageIcon getIcon() { + return null; + } + + public abstract String getDisplayText(); + ///////// + } + + private static class TagClassValueItem extends BeansXmlCompletionItem { + + private final String displayText, simpleName; + CCPaintComponent.DBElementPaintComponent paintComponent; + + public TagClassValueItem(int substitutionOffset, String fullName, String simpleName) { + super(substitutionOffset); + this.displayText = fullName; + this.simpleName = simpleName; + } + + @Override + public int getSortPriority() { + return 100; + } + + @Override + public CharSequence getSortText() { + return displayText; + } + + + @Override + public CharSequence getInsertPrefix() { + return displayText; + } + + @Override + public String getDisplayText() { + return simpleName + (simpleName.length() completors = new HashMap<>(); + + private BeansCompletionManager() { + setupCompletors(); + } + + private void setupCompletors() { + + + // Items for property names + BeansCompletor.JavaClassesCompletor javaClassCompletor = new BeansCompletor.JavaClassesCompletor(BeansCompletor.TAG.CLASS); + registerCompletor(BeansXmlConstants.CLASS, null, javaClassCompletor); + + BeansCompletor.JavaClassesCompletor stereotypeClassCompletor = new BeansCompletor.JavaClassesCompletor(BeansCompletor.TAG.STEREOTYPE); + registerCompletor(BeansXmlConstants.STEREOTYPE, null, stereotypeClassCompletor); + } + + private static final BeansCompletionManager INSTANCE = new BeansCompletionManager(); + + public static BeansCompletionManager getDefault() { + return INSTANCE; + } + + public int completeAttributeValues(CompletionContext context, List valueItems) { + int anchorOffset = -1; + + if(context.getTag() == null) { + return anchorOffset; + } + + String tagName = context.getTag().getNodeName(); + Token attrib = ContextUtilities.getAttributeToken(context.getDocumentContext()); + String attribName = attrib != null ? attrib.text().toString(): null; + + BeansCompletor completor = locateCompletor(tagName, attribName); + if (completor != null) { + valueItems.addAll(completor.doCompletion(context)); + if (completor.getAnchorOffset() != -1) { + anchorOffset = completor.getAnchorOffset(); + } + } + + return anchorOffset; + } + + public int completeValues(CompletionContext context, List valueItems) { + int anchorOffset = -1; + DocumentContext docContext = context.getDocumentContext(); + SyntaxElement curElem = docContext.getCurrentElement(); + SyntaxElement prevElem = docContext.getCurrentElement().getPrevious(); + + String tagName = curElem.getType() == Node.ELEMENT_NODE ? curElem.getNode().getNodeName() : null; + BeansCompletor completor = locateCompletor(tagName, null); + if (completor != null) { + valueItems.addAll(completor.doCompletion(context)); + if (completor.getAnchorOffset() != -1) { + anchorOffset = completor.getAnchorOffset(); + } + } + return anchorOffset; + } + + public int completeAttributes(CompletionContext context, List attributeItems) { + return -1; + } + + public int completeElements(CompletionContext context, List elementItems) { + return -1; + } + + + + private void registerCompletor(String tagName, String attribName, + BeansCompletor completor) { + completors.put(createRegisteredName(tagName, attribName), completor); + } + + private static String createRegisteredName(String nodeName, String attributeName) { + StringBuilder builder = new StringBuilder(); + if (nodeName != null && nodeName.trim().length() > 0) { + builder.append("/nodeName="); // NOI18N + builder.append(nodeName); + } else { + builder.append("/nodeName="); // NOI18N + builder.append("*"); // NOI18N + } + + if (attributeName != null && attributeName.trim().length() > 0) { + builder.append("/attribute="); // NOI18N + builder.append(attributeName); + } + + return builder.toString(); + } + + private BeansCompletor locateCompletor(String nodeName, String attributeName) { + String key = createRegisteredName(nodeName, attributeName); + if (completors.containsKey(key)) { + return completors.get(key); + } + + key = createRegisteredName("*", attributeName); // NOI18N + if (completors.containsKey(key)) { + return completors.get(key); + } + + return null; + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/BeansCompletionProvider.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/BeansCompletionProvider.java new file mode 100644 index 000000000000..e2cc635fc0f7 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/BeansCompletionProvider.java @@ -0,0 +1,483 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.completion; + +import com.sun.source.util.TreePath; +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.List; +import javax.lang.model.element.ElementKind; +import javax.lang.model.type.TypeKind; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Element; +import javax.swing.text.JTextComponent; +import javax.swing.text.StyledDocument; +import org.netbeans.api.editor.mimelookup.MimeRegistration; +import org.netbeans.api.java.lexer.JavaTokenId; +import static org.netbeans.api.java.lexer.JavaTokenId.BLOCK_COMMENT; +import static org.netbeans.api.java.lexer.JavaTokenId.JAVADOC_COMMENT; +import static org.netbeans.api.java.lexer.JavaTokenId.LINE_COMMENT; +import static org.netbeans.api.java.lexer.JavaTokenId.WHITESPACE; +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.JavaSource; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.editor.BaseDocument; +//import org.netbeans.modules.jakarta.web.beans.BeansDataLoader; +import org.netbeans.spi.editor.completion.CompletionProvider; +import static org.netbeans.spi.editor.completion.CompletionProvider.COMPLETION_QUERY_TYPE; +import org.netbeans.spi.editor.completion.CompletionResultSet; +import org.netbeans.spi.editor.completion.CompletionTask; +import org.netbeans.spi.editor.completion.support.AsyncCompletionQuery; +import org.netbeans.spi.editor.completion.support.AsyncCompletionTask; +import org.openide.ErrorManager; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.URLMapper; +import org.openide.util.Exceptions; + +/** + * + * @author sp153251 + */ +@MimeRegistration(mimeType = "text/x-beans-jakarta+xml", service = CompletionProvider.class)//NOI18N +public class BeansCompletionProvider implements CompletionProvider { + + @Override + public CompletionTask createTask(int queryType, JTextComponent component) { + if (queryType != CompletionProvider.COMPLETION_QUERY_TYPE && queryType !=CompletionProvider.COMPLETION_ALL_QUERY_TYPE) { + return null; + } + return new AsyncCompletionTask(new BeansCompletionQuery(queryType, component, component.getSelectionStart(), true), component); + } + + @Override + public int getAutoQueryTypes(JTextComponent component, String typedText) { + return 0;//will not appear automatically + } + + static int getRowFirstNonWhite(StyledDocument doc, int offset) + throws BadLocationException { + Element lineElement = doc.getParagraphElement(offset); + int start = lineElement.getStartOffset(); + while (start + 1 < lineElement.getEndOffset()) { + try { + if (doc.getText(start, 1).charAt(0) != ' ') { + break; + } + } catch (BadLocationException ex) { + throw (BadLocationException) new BadLocationException( + "calling getText(" + start + ", " + (start + 1) + + ") on doc of length: " + doc.getLength(), start).initCause(ex); + } + start++; + } + return start; + } + + static int indexOfWhite(char[] line) { + int i = line.length; + while (--i > -1) { + final char c = line[i]; + if (Character.isWhitespace(c)) { + return i; + } + } + return -1; + } + + static class BeansCompletionQuery extends AsyncCompletionQuery { + + private ArrayList resolvers; + private byte hasAdditionalItems = 0; //no additional items + private int anchorOffset; + private int queryType; + + public BeansCompletionQuery(int queryType, JTextComponent component, int caretOffset, boolean hasTask) { + this.queryType = queryType; + initResolvers(); + } + + private void initResolvers() { + //XXX temporary - should be registered somehow better + resolvers = new ArrayList(); + //resolvers.add(new DBCompletionContextResolver()); + } + + @Override + protected void query(CompletionResultSet resultSet, Document doc, int caretOffset) { + List completionItems = new ArrayList(); + + int anchorOffset = getCompletionItems(doc, caretOffset, completionItems); + resultSet.addAllItems(completionItems); + if (anchorOffset != -1) { + resultSet.setAnchorOffset(anchorOffset); + } + + resultSet.finish(); + } + + // This method is here for Unit testing purpose + int getCompletionItems(Document doc, int caretOffset, List completionItems) { + + int anchorOffset = -1; + CompletionContext context = new CompletionContext(doc, caretOffset); + + if (context.getCompletionType() == CompletionContext.CompletionType.NONE) { + return anchorOffset; + } + + switch (context.getCompletionType()) { +// case ATTRIBUTE_VALUE: +// anchorOffset = BeansCompletionManager.getDefault().completeAttributeValues(context, completionItems); +// break; +// case ATTRIBUTE: +// anchorOffset = BeansCompletionManager.getDefault().completeAttributes(context, completionItems); +// break; +// case TAG: +// anchorOffset = BeansCompletionManager.getDefault().completeElements(context, completionItems); +// break; + case VALUE: + anchorOffset = BeansCompletionManager.getDefault().completeValues(context, completionItems); + break; + } + + return anchorOffset; + } + + @Override + protected boolean canFilter(JTextComponent component) { + return false; + } + + @Override + protected void filter(CompletionResultSet resultSet) { + try { + resultSet.setAnchorOffset(anchorOffset); + } catch (Exception ex) { + Exceptions.printStackTrace(ex); + } + resultSet.finish(); + } + } + public final class Context { + + /** + * Text component + */ + private JTextComponent component; + CompilationController controller; + /** + * End position of the scanning - usually the caret position + */ + private int endOffset; + //private PersistenceUnit[] pus; + //private EntityMappings emaps; + private String completedMemberName, completedMemberJavaClassName; + private CCParser CCParser; + private CCParser.CC parsednn = null; + private CCParser.MD methodName = null; + + public Context(JTextComponent component, CompilationController controller, int endOffset, boolean autoPopup) { + this.component = component; + this.controller = controller; + this.endOffset = endOffset; + + FileObject documentFO = getFileObject(); + if (documentFO != null) { +// try { +// this.pus = PersistenceUtils.getPersistenceUnits(documentFO); +// } catch (IOException e) { +// ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); +// } + } + + this.CCParser = new CCParser(controller); + } + + /** + * Must be run under MDR transaction! + */ + public javax.lang.model.element.Element getJavaClass() { + TreePath path = null; +// try { +// path = getCompletionTreePath(getController(), endOffset, COMPLETION_QUERY_TYPE); +// } catch (IOException ex) { +// Exceptions.printStackTrace(ex); +// } + javax.lang.model.element.Element el = null; + try { + getController().toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + while ((el == null || !(ElementKind.CLASS == el.getKind() || ElementKind.INTERFACE == el.getKind())) && path != null) { + path.getCompilationUnit().getTypeDecls(); + el = getController().getTrees().getElement(path); + path = path.getParentPath(); + } + return el; + } + + public BaseDocument getBaseDocument() { + BaseDocument doc = (BaseDocument) component.getDocument(); + return doc; + } + + public FileObject getFileObject() { + try { + return URLMapper.findFileObject(getController().getCompilationUnit().getSourceFile().toUri().toURL()); + } catch (MalformedURLException ex) { + Exceptions.printStackTrace(ex); + } + return null; + } + + /** + * @return an arrat of PUs which this sourcefile belongs to. + */ +// public PersistenceUnit[] getPersistenceUnits() { +// return this.pus; +// } +// +// public EntityMappings getEntityMappings() { +// if (emaps == null) { +// FileObject documentFO = getFileObject(); +// this.emaps = PersistenceUtils.getEntityMappings(documentFO); +// } +// return this.emaps; +// } + + public int getCompletionOffset() { + return endOffset; + } + + public CCParser.CC getParsedAnnotation() { + synchronized (CCParser) { + if (parsednn == null) { + parsednn = CCParser.parseAnnotation(getCompletionOffset()); + } + return parsednn; + } + } + + public String getCompletedMemberClassName() { + if (completedMemberJavaClassName == null) { + initCompletedMemberContext(); + } + return completedMemberJavaClassName; + } + + public String getCompletedMemberName() { + if (completedMemberName == null) { + initCompletedMemberContext(); + } + return completedMemberName; + } + + private void initCompletedMemberContext() { + //parse the text behind the cursor and try to find identifiers. + //it seems to be impossible to use JMI model for this since it havily + //relies on the state of the source (whether it contains errors, which types etc.) + String type = null; + String genericType = null; + String propertyName = null; + CCParser nnp = new CCParser(getController()); //helper parser + + TokenSequence ts = getController().getTokenHierarchy().tokenSequence(JavaTokenId.language()); + ts.move(getCompletionOffset() + 1); + nextNonWhitespaceToken(ts); + Token ti = ts.token(); + while (ti != null && propertyName == null) { + javax.lang.model.element.Element el = null; +// try { +// el = getController().getTrees().getElement(getCompletionTreePath(getController(), ts.offset() + 1, CompletionProvider.COMPLETION_QUERY_TYPE)); +// } catch (IOException ex) { +// Exceptions.printStackTrace(ex); +// } + //skip all annotations between the CC offset and the completed member + if (el!=null && el.getKind() == ElementKind.ANNOTATION_TYPE) { + //parse to find NN end + CCParser.CC parsed = nnp.parseAnnotation(ts.offset() + 1); + if (parsed != null) { + //parse after the NN end (skip) + ts.move(parsed.getEndOffset()); + ti = ts.token(); + continue; + } + } + + //test whether we have just found a type and '<' character after + if (genericType != null && ti.id() == JavaTokenId.LT) { + //maybe a start of generic + ts.moveNext(); + Token ti2 = ts.token(); + if (ti2.id() == JavaTokenId.IDENTIFIER) { + //found generic + //genericType = ti2.getImage(); + //ti = ti.getNext(); //skip the next IDENTIFIER token so it is not considered as property name + } else { + //false alarm + genericType = null; + } + } else if (ti.id() == JavaTokenId.IDENTIFIER) { + if (type == null) { + //type = ti.getImage(); + genericType = type; + } else { + //propertyName = ti.getImage(); + } + } + ts.moveNext(); + ti = ts.token(); + } + + completedMemberName = propertyName; + completedMemberJavaClassName = genericType == null ? type : genericType; + } + + private void initMethodContext() { + TokenSequence ts = getController().getTokenHierarchy().tokenSequence(JavaTokenId.language()); + ts.move(getCompletionOffset()); + previousNonWhitespaceToken(ts); + Token ti = ts.token(); + int lparpassed = 0; + String mname = null; + while (ti != null) { + javax.lang.model.element.Element el = null; + if (ti.id() == JavaTokenId.LPAREN) { + lparpassed++; + } else if (ti.id() == JavaTokenId.IDENTIFIER) { + break;//so far we have only simple model for method parameters without identifier checks + } else if (ti.id() == JavaTokenId.RPAREN) { + lparpassed--; + } +// try { +// el = getController().getTrees().getElement(getCompletionTreePath(getController(), ts.offset(), CompletionProvider.COMPLETION_QUERY_TYPE)); +// } catch (IOException ex) { +// Exceptions.printStackTrace(ex); +// } + // + if (lparpassed > 0) { + if (el != null && el.getKind() == ElementKind.METHOD) {//we insde parameters section + //parse to find NN end + mname = el.getSimpleName().toString(); + break; + } else if (el != null && el.getKind() == ElementKind.CLASS && el.asType().getKind() == TypeKind.ERROR && (el.asType().toString().indexOf('.') > 0 && el.asType().toString().indexOf('.') < (el.asType().toString().length() - 1))) {//NOI18N + mname = el.getSimpleName().toString();//supposed method name in case of error + break; + } else { + break; + } + } + + // + + if (!ts.movePrevious()) { + break; + } + ti = ts.token(); + } + if (mname != null) { + Token literalToComplete = null; + Token titk = ts.token(); + JavaTokenId id; + do { + id = titk.id(); + //ignore whitespaces + if (id == JavaTokenId.WHITESPACE || id == JavaTokenId.LINE_COMMENT || id == JavaTokenId.BLOCK_COMMENT || id == JavaTokenId.JAVADOC_COMMENT) { + if (!ts.moveNext()) { + break; + } + titk = ts.token(); + continue; + } + int tokenOffset = titk.offset(getController().getTokenHierarchy()); + if(tokenOffset>getCompletionOffset()){ + + break; + } + + if(id == JavaTokenId.STRING_LITERAL){ + if((tokenOffset + titk.length())>getCompletionOffset()){ + //we complete this literal + literalToComplete = titk; + break; + } + } + + if (!ts.moveNext()) { + break; + } + titk = ts.token();//get next token + + } while (titk != null); + methodName = new CCParser.MD(mname, literalToComplete != null ? literalToComplete.text().toString() : null, literalToComplete != null ? literalToComplete.offset(getController().getTokenHierarchy()) : getCompletionOffset(), true, true); + } + } + + private TokenSequence nextNonWhitespaceToken(TokenSequence ts) { + while (ts.moveNext()) { + switch (ts.token().id()) { + case WHITESPACE: + case LINE_COMMENT: + case BLOCK_COMMENT: + case JAVADOC_COMMENT: + break; + default: + return ts; + } + } + return null; + } + + private TokenSequence previousNonWhitespaceToken(TokenSequence ts) { + do { + if (ts.token() != null) { + switch (ts.token().id()) { + case WHITESPACE: + case LINE_COMMENT: + case BLOCK_COMMENT: + case JAVADOC_COMMENT: + break; + default: + return ts; + } + } + } while (ts.movePrevious()); + return null; + } + + /** + * @return the controller + */ + public CompilationController getController() { + return controller; + } + + public CCParser.MD getMethod() { + if (methodName == null) { + initMethodContext(); + } + return methodName; + } + } + private static final String EMPTY = ""; //NOI18N +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/BeansCompletor.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/BeansCompletor.java new file mode 100644 index 000000000000..df87004a348a --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/BeansCompletor.java @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.completion; + +import java.io.IOException; +import java.util.*; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; +import javax.swing.text.Document; +import org.netbeans.api.java.source.ClassIndex; +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.JavaSource; +import org.netbeans.api.java.source.JavaSource.Phase; +import org.netbeans.api.java.source.Task; +import org.netbeans.modules.editor.NbEditorUtilities; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.openide.filesystems.FileObject; +import org.openide.util.Exceptions; + +/** + * Various completor for code completing XML tags and attributes + * + */ +public abstract class BeansCompletor { + + private int anchorOffset = -1; + + public enum TAG { + + CLASS, STEREOTYPE + }; + + TAG tag; + + public abstract List doCompletion(CompletionContext context); + + BeansCompletor(TAG tag) { + this.tag = tag; + } + + protected void setAnchorOffset(int anchorOffset) { + this.anchorOffset = anchorOffset; + } + + public int getAnchorOffset() { + return anchorOffset; + } + + /** + * A completor for completing class tag + */ + public static class JavaClassesCompletor extends BeansCompletor { + + JavaClassesCompletor(TAG tag) { + super(tag); + } + + @Override + public List doCompletion(final CompletionContext context) { + final List results = new ArrayList<>(); + try { + Document doc = context.getDocument(); + final String typedChars = context.getTypedPrefix(); + + JavaSource js = Utils.getJavaSource(doc); + if (js == null) { + return Collections.emptyList(); + } + FileObject fo = NbEditorUtilities.getFileObject(context.getDocument()); + doJavaCompletion(fo, js, results, typedChars, context.getCurrentTokenOffset()); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + + return results; + } + + private void doJavaCompletion(final FileObject fo, final JavaSource js, final List results, + final String typedPrefix, final int substitutionOffset) throws IOException { + js.runUserActionTask(new Task() { + + @Override + public void run(CompilationController cc) throws Exception { + cc.toPhase(Phase.ELEMENTS_RESOLVED); + Set> declaredTypes = null; + declaredTypes = cc.getClasspathInfo().getClassIndex().getDeclaredTypes(typedPrefix, ClassIndex.NameKind.PREFIX, Collections.singleton(ClassIndex.SearchScope.SOURCE));//to have dependencies: EnumSet.allOf(ClassIndex.SearchScope.class) + + // add classes + if (declaredTypes != null && declaredTypes.size() > 0) { + for (ElementHandle cl : declaredTypes) { + ElementKind kind = cl.getKind(); + switch (tag) { + case CLASS: { + + if (kind == ElementKind.CLASS) { + TypeElement te = cl.resolve(cc); + if (isAlternative(te)) { + + BeansCompletionItem item = BeansCompletionItem.createBeansTagValueItem(substitutionOffset-typedPrefix.length(), cl.getQualifiedName(), te.getSimpleName().toString()); + results.add(item); + } + } + + } + break; + case STEREOTYPE: { + if (kind == ElementKind.ANNOTATION_TYPE) { + TypeElement te = cl.resolve(cc); + if (isAlternative(te)) { + + BeansCompletionItem item = BeansCompletionItem.createBeansTagValueItem(substitutionOffset-typedPrefix.length(), cl.getQualifiedName(), te.getSimpleName().toString()); + results.add(item); + } + } + } + break; + } + } + } + } + }, true); + + setAnchorOffset(substitutionOffset); + } + } + + private static boolean isAlternative(TypeElement te) { + List annotationMirrors = te.getAnnotationMirrors(); + for (AnnotationMirror annotation : annotationMirrors) { + if (annotation.getAnnotationType().asElement() instanceof TypeElement) { + String typeName = ((TypeElement) annotation.getAnnotationType().asElement()).getQualifiedName().toString(); + if (AnnotationUtil.ALTERNATVE.equals(typeName)) { + return true; + } + } + } + return false; + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/BeansXmlConstants.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/BeansXmlConstants.java new file mode 100644 index 000000000000..58714d20a80f --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/BeansXmlConstants.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.jakarta.web.beans.completion; + +/** + * + * @author sp153251 + */ +public class BeansXmlConstants { + + public static String ALTERNATIVES = "alternatives";//NOI18N + public static String CLASS = "class";//NOI18N + public static String STEREOTYPE = "stereotype";//NOI18N +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/CCPaintComponent.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/CCPaintComponent.java new file mode 100644 index 000000000000..70e764a25f15 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/CCPaintComponent.java @@ -0,0 +1,316 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.completion; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.font.TextAttribute; +import java.text.AttributedString; +import java.util.HashMap; +import java.util.Map; +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JPanel; + +/** + * + * @author Dusan Balek, Andrei Badea, Marek Fukala + */ +public class CCPaintComponent extends JPanel { + + private static final int ICON_WIDTH = 16; + private static final int ICON_TEXT_GAP = 5; + + protected int drawX; + + protected int drawY; + + protected int drawHeight; + + private Font drawFont; + + private int fontHeight; + + private int ascent; + + private Map widths; + + private FontMetrics fontMetrics; + + private boolean isSelected; + + private boolean isDeprecated; + + private static final String THROWS = " throws "; // NOI18N + + + private static final String[] frequentWords = new String[] { + "", " ", "[]", "(", ")", ", ", "String", THROWS // NOI18N + }; + + public static final Color KEYWORD_COLOR = Color.darkGray; + public static final Color TYPE_COLOR = Color.black; + + /** When an outer method/constructor is rendered. */ + static final Color ENCLOSING_CALL_COLOR = Color.gray; + /** When an active parameter gets rendered. */ + static final Color ACTIVE_PARAMETER_COLOR = Color.black; + + public CCPaintComponent(){ + super(); + setOpaque(true); + setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 3)); + } + + protected void setSelected(boolean isSelected){ + this.isSelected = isSelected; + } + + protected void setDeprecated(boolean isDeprecated){ + this.isDeprecated = isDeprecated; + } + + protected boolean isSelected(){ + return isSelected; + } + + protected boolean isDeprecated(){ + return isDeprecated; + } + + @Override + public void paintComponent(Graphics g) { + // clear background + g.setColor(getBackground()); + java.awt.Rectangle r = g.getClipBounds(); + g.fillRect(r.x, r.y, r.width, r.height); + draw(g); + } + + protected void draw(Graphics g){ + } + + + /** Draw the icon if it is valid for the given type. + * Here the initial drawing assignments are also done. + */ + protected void drawIcon(Graphics g, Icon icon) { + Insets i = getInsets(); + if (i != null) { + drawX = i.left; + drawY = i.top; + } else { + drawX = 0; + drawY = 0; + } + + if (icon != null) { + if (g != null) { + icon.paintIcon(this, g, drawX, drawY); + } + drawHeight = Math.max(fontHeight, icon.getIconHeight()); + } else { + drawHeight = fontHeight; + } + drawX += ICON_WIDTH + ICON_TEXT_GAP; + if (i != null) { + drawHeight += i.bottom; + } + drawHeight += drawY; + drawY += ascent; + } + + protected void drawString(Graphics g, String s){ + drawString(g, s, false); + } + + /** Draw string using the foreground color */ + protected void drawString(Graphics g, String s, boolean strike) { + if (g != null) { + g.setColor(getForeground()); + } + drawStringToGraphics(g, s, null, strike); + } + + + /** Draw string with given color which is first possibly modified + * by calling getColor() method to care about selection etc. + */ + protected void drawString(Graphics g, String s, Color c) { + if (g != null) { + g.setColor(getColor(s, c)); + } + drawStringToGraphics(g, s); + } + + protected void drawString(Graphics g, String s, Color c, Font font, boolean strike) { + if (g != null) { + g.setColor(getColor(s, c)); + g.setFont(font); + } + drawStringToGraphics(g, s, font, strike); + if (g != null) { + g.setFont(drawFont); + } + + } + + protected void drawTypeName(Graphics g, String s, Color c) { + if (g == null) { + drawString(g, " "); // NOI18N + drawString(g, s, c); + } else { + int w = getWidth() - getWidth(s) - drawX; + int spaceWidth = getWidth(" "); // NOI18N + if (w > spaceWidth * 2) { + drawX = getWidth() - 2 * spaceWidth - getWidth(s); + } else { + drawX = getWidth() - 2 * spaceWidth - getWidth(s) - getWidth("... "); // NOI18N + g.setColor(getBackground()); + g.fillRect(drawX, 0, getWidth() - drawX, getHeight()); + drawString(g, "... ", c); // NOI18N + } + drawString(g, s, c); + } + } + + protected void drawStringToGraphics(Graphics g, String s) { + drawStringToGraphics(g, s, null, false); + } + + protected void drawStringToGraphics(Graphics g, String s, Font font, boolean strike) { + if (g != null) { + if (!strike){ + g.drawString(s, drawX, drawY); + }else{ + Graphics2D g2 = ((Graphics2D)g); + AttributedString strikeText = new AttributedString(s); + strikeText.addAttribute(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON); + strikeText.addAttribute(TextAttribute.FONT, g.getFont()); + g2.drawString(strikeText.getIterator(), drawX, drawY); + } + } + drawX += getWidth(s, font); + } + + protected int getWidth(String s) { + Integer i = (Integer)widths.get(s); + if (i != null) { + return i; + } else { + if (s == null) { + s = ""; + } + return fontMetrics.stringWidth(s); + } + } + + protected int getWidth(String s, Font font) { + if (font == null) { + return getWidth(s); + } + return getFontMetrics(font).stringWidth(s); + } + + protected Color getColor(String s, Color defaultColor) { + return isSelected ? getForeground() + : defaultColor; + } + + private void storeWidth(String s) { + fontMetrics.stringWidth(s); + } + + @Override + public void setFont(Font font) { + super.setFont(font); + + fontMetrics = this.getFontMetrics(font); + fontHeight = fontMetrics.getHeight(); + ascent = fontMetrics.getAscent(); + if (widths != null) { + widths.clear(); + } else { + widths = new HashMap<>(); + } + for (int i = 0; i < frequentWords.length; i++) { + storeWidth(frequentWords[i]); + } + drawFont = font; + } + + protected Font getDrawFont(){ + return drawFont; + } + + @Override + public Dimension getPreferredSize() { + draw(null); + Insets i = getInsets(); + if (i != null) { + drawX += i.right; + } + if (drawX > getMaximumSize().width) { + drawX = getMaximumSize().width; + } + return new Dimension(drawX, drawHeight); + } + + public static class NbStringPaintComponent extends CCPaintComponent { + + private String str; + + public void setString(String str){ + this.str = str; + } + + @Override + protected void draw(Graphics g){ + drawIcon(g, null); + drawString(g, str, TYPE_COLOR); + } + + } + + public static final class DBElementPaintComponent extends NbStringPaintComponent { + + } + + + public static final class BeansElementPaintComponent extends NbStringPaintComponent { + + private String puName; + + public void setContent(String puName) { + this.puName = puName; + } + + @Override + protected void draw(Graphics g){ + + drawString(g, puName, Color.BLACK, getDrawFont().deriveFont(Font.BOLD), false); + } + + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/CCParser.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/CCParser.java new file mode 100644 index 000000000000..899bd8cc030b --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/CCParser.java @@ -0,0 +1,444 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.completion; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.netbeans.api.java.lexer.JavaTokenId; +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; + +/** + * Builds an annotations tree containg NN name and attribs map. Supports nested annotations. + * + * @author Marek Fukala + */ + +public class CCParser { + + //parser states + private static final int INIT = 0; + private static final int NN = 1; //@ + private static final int ERROR = 2; + private static final int NNNAME = 3; //@Table + private static final int INNN = 4; //@Table( + private static final int ATTRNAME = 5; //@Table(name + private static final int EQ = 6; //@Table(name= + private static final int ATTRVALUE = 7; //@Table(name="hello" || @Table(name=@ + + private final CompilationController controller; + + CCParser(CompilationController controller) { + this.controller = controller; + } + + public CC parseAnnotation(int offset) { + int nnStart = findAnnotationStart(offset); + if(nnStart == -1) { + return null; + } else { + return parseAnnotationOnOffset(nnStart); + } + } + + /** very simple annotations parser */ + private CC parseAnnotationOnOffset(int offset) { + int state = INIT; + TokenSequence ts = controller.getTokenHierarchy().tokenSequence(JavaTokenId.language()); + ts.moveStart(); + if (ts.move(offset) == 0) { + if(!ts.moveNext()) { + ts.movePrevious(); + } + } + Token titk = ts.token(); + JavaTokenId id = titk.id(); + + assert id == JavaTokenId.AT; + + int nnstart = ts.offset(); + int nnend; + String nnName = null; + String currAttrName = null; + String currAttrValue = null; + int currAttrStartOffset = -1; + boolean currAttrQuated = false; + int lparopened = 0; + + List attrs = new ArrayList(5); + //helper var + int eqOffset = -1; + + do { + id = titk.id(); + //ignore whitespaces + if(id == JavaTokenId.WHITESPACE || id==JavaTokenId.LINE_COMMENT || id==JavaTokenId.BLOCK_COMMENT || id==JavaTokenId.JAVADOC_COMMENT) { + if(!ts.moveNext()) { + break; + } + titk = ts.token(); + continue; + } + + switch(state) { + case INIT: + switch(id) { + case AT: + state = NN; + break; + default: + state = ERROR; + } + break; + case NN: + switch(id) { + case IDENTIFIER: + state = NNNAME; + nnName = titk.text().toString(); + break; + default: + state = ERROR; + } + break; + case NNNAME: + switch(id) { + case LPAREN: + state = INNN; + break; + case DOT: + case IDENTIFIER: + //add the token image to the NN name + nnName += titk.text().toString(); + break; + default: + //we are in NN name, but no parenthesis came + //this mean either error or annotation without parenthesis like @Id + nnend = nnstart + "@".length() + nnName.length(); + CC newNN = new CC(nnName, attrs, nnstart, nnend); + return newNN; + } + break; + case INNN: + switch(id) { + case IDENTIFIER: + currAttrName = titk.text().toString(); + state = ATTRNAME; + break; + //case JavaTokenContext.RPAREN_ID: + case COMMA: + //just consume, still in INNN + break; + default: + //we reached end of the annotation, or error + state = ERROR; + break; + } + break; + case ATTRNAME: + switch(id) { + case EQ: + state = EQ; + currAttrValue = ""; + currAttrStartOffset = -1; + currAttrQuated = false; + eqOffset = ts.offset(); + break; + default: + state = ERROR; + } + break; + case EQ: + switch(id) { + case STRING_LITERAL: + currAttrStartOffset = currAttrStartOffset<0 ? ts.offset() : currAttrStartOffset; + currAttrQuated = true;//currently is used in cc and we support qq for one literal only, may need to be revieved later for "combined" cases + currAttrValue += Utils.unquote(titk.text().toString()); + break; + case DOT: + case IDENTIFIER: + //need to collect data, do not switch to INNN here + //multidot identifier can be expected, and it may be summ with literals and with parensis + currAttrStartOffset = currAttrStartOffset<0 ? ts.offset() : currAttrStartOffset; + currAttrValue += titk.text().toString(); + break; + case PLUS: + currAttrStartOffset = currAttrStartOffset<0 ? ts.offset() : currAttrStartOffset; + currAttrValue += titk.text().toString(); + break; + case LPAREN: + lparopened++; + currAttrStartOffset = currAttrStartOffset<0 ? ts.offset() : currAttrStartOffset; + currAttrValue += titk.text().toString(); + break; + case AT: + //nested annotation + CC nestedNN = parseAnnotationOnOffset(ts.offset()); + attrs.add(new NNAttr(currAttrName, nestedNN, ts.offset(), false)); + state = INNN; + //I need to skip what was parsed in the nested annotation in this parser + if (ts.move(nestedNN.getEndOffset()) == 0) { + if(!ts.moveNext()) { + ts.movePrevious(); + } + } + titk = ts.token(); + continue; //next loop + case RPAREN: + lparopened--; + if(lparopened<0){ + state = INNN; + attrs.add(new NNAttr(currAttrName, currAttrValue, currAttrStartOffset, currAttrQuated)); + ts.movePrevious(); + break; + } + case COMMA: + state = INNN; + attrs.add(new NNAttr(currAttrName, currAttrValue, currAttrStartOffset, currAttrQuated)); + break; + default: + //ERROR => recover + //set the start offset of the value to the offset of the equator + 1 + attrs.add(new NNAttr(currAttrName, "", eqOffset + 1, false)); + state = INNN; + break; + } + } + + if(state == ERROR) { + //return what we parser so far to be error recovery as much as possible + nnend = ts.offset() + titk.text().toString().length(); + CC newNN = new CC(nnName, attrs, nnstart, nnend); + return newNN; + } + if(!ts.moveNext()) { + break; + } + titk = ts.token();//get next token + + } while(titk != null); + + + + return null; + } + + + private int findAnnotationStart(int offset) { + + if(offset>0){//0 can't contain any '@' before + + int parentCount = -100; + + TokenSequence ts = controller.getTokenHierarchy().tokenSequence(JavaTokenId.language()); + if (ts.move(offset) == 0 || !ts.moveNext()) { + ts.movePrevious(); + } + int len = offset - ts.offset(); + if (len > 0 && (ts.token().id() == JavaTokenId.IDENTIFIER || + ts.token().id().primaryCategory().startsWith("keyword") || //NOI18N + ts.token().id().primaryCategory().startsWith("string") || //NOI18N + ts.token().id().primaryCategory().equals("literal")) //NOI18N + && ts.token().length() >= len) { //TODO: Use isKeyword(...) when available + } + Token titk = ts.token(); + while(titk != null) { + JavaTokenId id = titk.id(); + + if(id == JavaTokenId.RPAREN) { + if(parentCount == -100) { + parentCount = 0; + } + parentCount++; + } else if(id == JavaTokenId.LPAREN) { + if(parentCount == -100) { + parentCount = 0; + } + parentCount--; + } else if(id == JavaTokenId.AT) { + if(parentCount == -1 || parentCount == -100) { //needed if offset is not within annotation content + return ts.offset(); + } + } + if (!ts.movePrevious()) { + break; + } + titk = ts.token(); + } + } + + return -1; + } + + public static class NNAttr { + private String name; + private Object value; + private int valueOffset; + private boolean quoted; + + NNAttr(String name, Object value, int valueOffset, boolean quoted) { + this.name = name; + this.value = value; + this.valueOffset = valueOffset; + this.quoted = quoted; + } + + public String getName() { + return name; + } + + public Object getValue() { + return value; + } + + public int getValueOffset() { + return valueOffset; + } + + public boolean isValueQuoted() { + return quoted; + } + + } + + public static class CC { + + private String name; + private List attributes; + private int startOffset, endOffset; + + public CC(String name, List attributes, int startOffset, int endOffset) { + this.name = name; + this.attributes = attributes; + this.startOffset = startOffset; + this.endOffset = endOffset; + } + + public String getName() { + return name; + } + + public List getAttributesList() { + return attributes; + } + + public Map getAttributes() { + HashMap map = new HashMap(); + for(NNAttr nnattr : getAttributesList()) { + map.put(nnattr.getName(), nnattr.getValue()); + } + return map; + } + + public NNAttr getAttributeForOffset(int offset) { + NNAttr prevnn = null; + for(NNAttr nnattr : getAttributesList()) { + if(nnattr.getValueOffset() >= offset) { + break; + } + prevnn = nnattr; + } + + if(prevnn == null) { + return null; + } + + int nnEndOffset = prevnn.getValueOffset() + prevnn.getValue().toString().length() + (prevnn.isValueQuoted() ? 2 : 0); + if(nnEndOffset >= offset && prevnn.getValueOffset() <= offset) { + return prevnn; + } else { + return null; + } + } + + public int getStartOffset() { + return startOffset; + } + + public int getEndOffset() { + return endOffset; + } + + @Override + public String toString() { + //just debug purposes -> no need for superb performance + String text = "@" + getName() + " [" + getStartOffset() + " - " + getEndOffset() + "]("; + for(NNAttr nnattr : getAttributesList()) { + String key = nnattr.getName(); + String value = nnattr.getValue().toString(); + text+=key+"="+value+ " (" + nnattr.getValueOffset() + ") ,"; + } + text = text.substring(0, text.length() -1); + text+=")"; + return text; + } + } + + public static class MD{ + private final String methodName; + private final boolean withQ; + private final boolean insideParam; + private int valueOffset; + private final String value; + public MD(String methodName, String value, int valueOffset, boolean withQ, boolean insideParam){ + this.methodName = methodName; + this.withQ = withQ; + this.insideParam = insideParam; + this.valueOffset = valueOffset; + this.value = value; + } + + /** + * @return the methodName + */ + public String getMethodName() { + return methodName; + } + + /** + * @return the withQ + */ + public boolean isWithQ() { + return withQ; + } + + /** + * @return the insideParam + */ + public boolean isInsideParam() { + return insideParam; + } + + /** + * @return the valueOffset + */ + public int getValueOffset() { + return valueOffset; + } + + public String getValue() { + return value; + } + } + public static final String CREATE_QUERY="createQuery";//NOI18N + public static final String CREATE_NAMEDQUERY="createNamedQuery";//NOI18N + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/CompletionContext.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/CompletionContext.java new file mode 100644 index 000000000000..763cce75f93a --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/CompletionContext.java @@ -0,0 +1,295 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.jakarta.web.beans.completion; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; +import org.openide.util.Exceptions; +import org.w3c.dom.Node; +import org.w3c.dom.Text; + +/** + * Tracks context information for a code completion scenario + */ +public class CompletionContext { + private List existingAttributes; + + public static enum CompletionType { + TAG, + VALUE, + ATTRIBUTE, + ATTRIBUTE_VALUE, + NONE + }; + + private static final Logger LOGGER = Logger.getLogger(CompletionContext.class.getName()); + private CompletionType completionType = CompletionType.NONE; + private Document doc; + private int caretOffset; + private DocumentContext documentContext; + private String typedChars = ""; + private char lastTypedChar; + private XMLSyntaxSupport support; + + public CompletionContext(Document doc, int caretOffset) { + this.doc = doc; + this.caretOffset = caretOffset; + + try { + this.support = XMLSyntaxSupport.getSyntaxSupport(doc); + } catch (ClassCastException cce) { + LOGGER.log(Level.FINE, cce.getMessage()); + this.support = XMLSyntaxSupport.createSyntaxSupport(doc); + } + this.documentContext = EditorContextFactory.getDocumentContext(doc, caretOffset); + this.lastTypedChar = support.lastTypedChar(); + try { + initContext(); + } catch (BadLocationException ex) { + // ignore + } + } + + private void initContext() throws BadLocationException { + Token token = documentContext.getCurrentToken(); + if(token == null) + return; + + boolean tokenBoundary = (documentContext.getCurrentTokenOffset() == caretOffset) + || ((documentContext.getCurrentTokenOffset() + token.length()) == caretOffset); + + XMLTokenId id = token.id(); + SyntaxElement element = documentContext.getCurrentElement(); + String chars = token.text().toString().trim(); + int tOffset = documentContext.getCurrentTokenOffset(); + + switch (id) { + // + case TEXT: + Token previousTokenItem = support.getPreviousToken(tOffset); + if (previousTokenItem == null) { + completionType = CompletionType.NONE; + break; + } + String text = previousTokenItem.text().toString().trim(); + if (chars != null && chars.equals("") && + text.equals("/>")) { // NOI18N + completionType = CompletionType.NONE; + break; + } + if (chars != null && chars.equals("") && + text.equals(">")) { // NOI18N + completionType = CompletionType.VALUE; + break; + } + if (chars != null && !chars.startsWith("<") && + text.equals(">")) { // NOI18N + + completionType = CompletionType.VALUE; + typedChars = chars.substring(0, caretOffset - tOffset); + break; + } + if (chars != null && !chars.equals("<") && + text.equals(">")) { // NOI18N + completionType = CompletionType.NONE; + break; + } + if (chars != null && chars.startsWith("<")) { // NOI18N + typedChars = chars.substring(1); + } + completionType = CompletionType.TAG; + break; + + //start tag of an element + case TAG: + String tagName = element.getNode().getNodeName(); + if (support.isEndTag(element)) { + completionType = CompletionType.NONE; + break; + } + if (support.isEmptyTag(element)) { + if (chars.trim().equals("/>")) { + completionType = CompletionType.NONE; + break; + } + if (element.getElementOffset() + 1 == this.caretOffset) { + completionType = CompletionType.TAG; + break; + } + if (caretOffset > element.getElementOffset() + 1 && + caretOffset <= element.getElementOffset() + 1 + tagName.length()) { + completionType = CompletionType.TAG; + typedChars = tagName; + break; + } + completionType = CompletionType.ATTRIBUTE; + break; + } + + if (support.isStartTag(element)) { + if (token != null && + chars.equals(">")) { + completionType = CompletionType.NONE; + break; + } + if (token != null && + chars.startsWith(" previous = support.getPreviousToken(tOffset); + typedChars = previous.text().toString().trim(); + completionType = CompletionType.VALUE; + break; + } + } + + if (lastTypedChar == '>') { + completionType = CompletionType.VALUE; + break; + } + completionType = CompletionType.TAG; + break; + + //user enters an attribute name + case ARGUMENT: + completionType = CompletionType.ATTRIBUTE; + typedChars = chars.substring(0, caretOffset - tOffset); + break; + + //some random character + case CHARACTER: + //user enters = character, we should ignore all other operators + case OPERATOR: + completionType = CompletionType.NONE; + break; + //user enters either ' or " + case VALUE: + if(!tokenBoundary) { + completionType = CompletionType.ATTRIBUTE_VALUE; + typedChars = chars.substring(1, caretOffset - tOffset); + } else { + completionType = CompletionType.NONE; + } + break; + + //user enters white-space character + case WS: + completionType = CompletionType.NONE; + Token prev = support.skip(tOffset, false, XMLTokenId.WS); + if (prev == null) { + completionType = CompletionType.NONE; + break; + } + if(prev.id() == XMLTokenId.ARGUMENT) { + typedChars = prev.text().toString(); + completionType = CompletionType.ATTRIBUTE; + } else if ((prev.id() == XMLTokenId.VALUE) || + (prev.id() == XMLTokenId.TAG)) { + completionType = CompletionType.ATTRIBUTE; + } + break; + + default: + completionType = CompletionType.NONE; + break; + } + } + + public CompletionType getCompletionType() { + return completionType; + } + + public String getTypedPrefix() { + return typedChars; + } + + public Document getDocument() { + return this.doc; + } + + public DocumentContext getDocumentContext() { + return this.documentContext; + } + + public int getCaretOffset() { + return caretOffset; + } + + public Node getTag() { + SyntaxElement element = documentContext.getCurrentElement(); + return element.getType() == Node.ELEMENT_NODE ? element.getNode() : null; + } + + public Token getCurrentToken() { + return documentContext.getCurrentToken(); + } + + public int getCurrentTokenOffset() { + return documentContext.getCurrentTokenOffset(); + } + + private List getExistingAttributesLocked(TokenSequence ts) { + List existingAttributes = new ArrayList(); + while (ts.movePrevious()) { + Token item = ts.token(); + XMLTokenId tokenId = item.id(); + if (tokenId == XMLTokenId.TAG) { + break; + } + if (tokenId == XMLTokenId.ARGUMENT) { + existingAttributes.add(item.text().toString()); + } + } + return existingAttributes; + } + + public List getExistingAttributes() { + if (existingAttributes == null) { + try { + existingAttributes = support.runWithSequence( + documentContext.getCurrentTokenOffset(), + this::getExistingAttributesLocked + ); + } catch (BadLocationException ex) { + Exceptions.printStackTrace(ex); + } + } + return existingAttributes; + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/CompletionContextResolver.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/CompletionContextResolver.java new file mode 100644 index 000000000000..c5f7b3363d65 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/CompletionContextResolver.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.jakarta.web.beans.completion; + +import java.util.List; + +/** + * + * @author marek + */ +public interface CompletionContextResolver { + + /** returns a list of completion items based on the given context */ + public List resolve(BeansCompletionProvider.Context ctx); + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/ContextUtilities.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/ContextUtilities.java new file mode 100644 index 000000000000..7b38722439f8 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/ContextUtilities.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.jakarta.web.beans.completion; + +import javax.swing.text.BadLocationException; +import javax.xml.XMLConstants; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.xml.lexer.XMLTokenId; +import static org.netbeans.api.xml.lexer.XMLTokenId.ARGUMENT; +import static org.netbeans.api.xml.lexer.XMLTokenId.OPERATOR; +import org.netbeans.editor.TokenItem; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.TagElement; +import org.w3c.dom.Node; + +/** + * + * @author Rohan Ranade + */ +public final class ContextUtilities { + + private ContextUtilities() { + } + + public static boolean isValueToken(Token currentToken) { + if(currentToken != null) { + if (currentToken.id() == XMLTokenId.VALUE) { + return true; + } + } + + return false; + } + + public static boolean isTagToken(Token currentToken) { + if(currentToken != null) { + if (currentToken.id() == XMLTokenId.TAG) { + return true; + } + } + + return false; + } + + public static boolean isAttributeToken(Token currentToken) { + if(currentToken != null) { + if (currentToken.id() == XMLTokenId.ARGUMENT) { + return true; + } + } + + return false; + } + + public static Token getAttributeToken(DocumentContext context) { + if(context.getCurrentToken() == null ) { + return null; + } + return context.getSyntaxSupport().getAttributeToken(context.getCurrentTokenOffset()); + } + + public static String getAttributeTokenImage(DocumentContext context) { + Token tok = getAttributeToken(context); + if(tok != null) { + return tok.text().toString(); + } + + return null; + } + + /** + * Returns the prefix from the element's tag. + */ + public static String getPrefixFromTag(String tagName) { + if(tagName == null) return null; + return (tagName.indexOf(":") == -1) ? null : // NOI18N + tagName.substring(0, tagName.indexOf(":")); // NOI18N + } + + /** + * Returns the local name from the element's tag. + */ + public static String getLocalNameFromTag(String tagName) { + if(tagName == null) return null; + return (tagName.indexOf(":") == -1) ? tagName : // NOI18N + tagName.substring(tagName.indexOf(":")+1, tagName.length()); // NOI18N + } + + /** + * Returns any prefix declared with this namespace. For example, if + * the namespace was declared as xmlns:po, the prefix 'po' will be returned. + * Returns null for declaration that contains no prefix. + */ + public static String getPrefixFromNamespaceDeclaration(String namespace) { + if (!namespace.startsWith(XMLConstants.XMLNS_ATTRIBUTE)) return null; + int xmlnsLength = XMLConstants.XMLNS_ATTRIBUTE.length(); + if (namespace.length() == xmlnsLength) { + return ""; // NOI18N + } + if (namespace.charAt(xmlnsLength) == ':') { + return namespace.substring(xmlnsLength + 1); + } + return null; + } + + public static String getPrefixFromNodeName(String nodeName) { + int colonIndex = nodeName.indexOf(':'); + if (colonIndex <= 0) { + return null; + } + return nodeName.substring(0, colonIndex); + } + + public static SyntaxElement getRoot(SyntaxElement se) { + SyntaxElement root = null; + while( se != null) { + if(se.getType() == Node.ELEMENT_NODE && + ((TagElement)se).isStart()) { + root = se; + } + se = se.getPrevious(); + } + + return root; + } + +} + diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/DocumentContext.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/DocumentContext.java new file mode 100644 index 000000000000..ed523c27bb1f --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/DocumentContext.java @@ -0,0 +1,236 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.jakarta.web.beans.completion; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map.Entry; +import java.util.Stack; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.xml.lexer.XMLTokenId; +import org.netbeans.editor.BaseDocument; +import org.netbeans.editor.TokenItem; +import org.netbeans.modules.xml.text.api.dom.SyntaxElement; +import org.netbeans.modules.xml.text.api.dom.XMLSyntaxSupport; +import org.w3c.dom.Attr; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + * Tracks context information for XML files + * + * @author Rohan Ranade + */ +public class DocumentContext { + + //public static final String PREFIX = "ns"; //NOI18N + //public static final String XSI_SCHEMALOCATION = "schemaLocation"; //NOI18N + //public static final String XSI_NONS_SCHEMALOCATION = "noNamespaceSchemaLocation"; //NOI18N + + private static final Logger LOGGER = Logger.getLogger(DocumentContext.class.getName()); + private Document document; + private XMLSyntaxSupport syntaxSupport; + private int caretOffset = -1; + private SyntaxElement element; + private Token token; + private int tokenOffset; + private boolean valid = false; + private SyntaxElement docRoot; + private String defaultNamespace; + private HashMap declaredNamespaces = + new HashMap(); + private String schemaLocation; + private String noNamespaceSchemaLocation; + + DocumentContext(Document document) { + this.document = document; + try { + this.syntaxSupport = XMLSyntaxSupport.getSyntaxSupport(document); + } catch (ClassCastException cce) { + LOGGER.log(Level.FINE, cce.getMessage()); + this.syntaxSupport = XMLSyntaxSupport.createSyntaxSupport(document); + } + } + + public void reset(int caretOffset) { + this.caretOffset = caretOffset; + initialize(); + } + + private void initialize() { + valid = true; + declaredNamespaces.clear(); + try { + element = syntaxSupport.getElementChain(caretOffset); + int[] bounds = new int[1]; + token = syntaxSupport.getTokenAtPosition(caretOffset, bounds); + tokenOffset = bounds[0]; + this.docRoot = ContextUtilities.getRoot(element); + populateNamespaces(); + } catch (BadLocationException ex) { + // No context support available in this case + valid = false; + } + } + + public boolean isValid() { + return this.valid; + } + + public XMLTokenId getCurrentTokenId() { + if (isValid()) { + return token.id(); + } else { + return null; + } + } + + public Token getCurrentToken() { + if (isValid()) { + return token; + } else { + return null; + } + } + + public String getCurrentTokenImage() { + if (isValid()) { + return token.text().toString(); + } else { + return null; + } + } + + public SyntaxElement getCurrentElement() { + return this.element; + } + + public Document getDocument() { + return this.document; + } + + public String lookupNamespacePrefix(String prefix) { + return declaredNamespaces.get(prefix); + } + + public String getNamespacePrefix(String namespace) { + for(Entry entry : declaredNamespaces.entrySet()) { + if(entry.getValue().equals(namespace)) { + return entry.getKey(); + } + } + + return null; + } + + public Collection getDeclaredNamespaces() { + return declaredNamespaces.values(); + } + + public SyntaxElement getDocRoot() { + return docRoot; + } + + public int getCaretOffset() { + return this.caretOffset; + } + + public int getCurrentTokenOffset() { + return tokenOffset; + } + + private void populateNamespaces() { + // Find the a start or empty tag just before the current syntax element. + SyntaxElement element = this.element; + while (element != null && !syntaxSupport.isStartTag(element) && !syntaxSupport.isEmptyTag(element)) { + element = element.getPrevious(); + } + if (element == null) { + return; + } + + // To find all namespace declarations active at the caret offset, we + // need to look at xmlns attributes of the current element and its ancestors. + Node node = (Node)element; + while (node != null && element != null) { + if (syntaxSupport.isStartTag(element) || syntaxSupport.isEmptyTag(element)) { + NamedNodeMap attributes = node.getAttributes(); + for (int index = 0; index < attributes.getLength(); index++) { + Attr attr = (Attr) attributes.item(index); + String attrName = attr.getName(); + String attrValue = attr.getValue(); + if (attrName == null || attrValue == null) { + continue; + } + String prefix = ContextUtilities.getPrefixFromNamespaceDeclaration(attrName); + if (prefix == null) { + continue; + } + // Avoid overwriting a namespace declaration "closer" to the caret offset. + if (!declaredNamespaces.containsKey(prefix)) { + declaredNamespaces.put(prefix, attrValue); + } + } + } + node = node.getParentNode(); + } + } + + public String getNoNamespaceSchemaLocation() { + return noNamespaceSchemaLocation; + } + + public String getSchemaLocation() { + return schemaLocation; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final DocumentContext other = (DocumentContext) obj; + if (this.document != other.document && (this.document == null || !this.document.equals(other.document))) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 61 * hash + (this.document != null ? this.document.hashCode() : 0); + return hash; + } + + public XMLSyntaxSupport getSyntaxSupport() { + return syntaxSupport; + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/EditorContextFactory.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/EditorContextFactory.java new file mode 100644 index 000000000000..7b788a91bd4e --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/EditorContextFactory.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.jakarta.web.beans.completion; + +import java.util.Map; +import java.util.WeakHashMap; +import javax.swing.text.Document; + +/** + * + * @author Rohan Ranade + */ +public final class EditorContextFactory { +// private static Map contextCache = +// new WeakHashMap(); + + public static DocumentContext getDocumentContext(Document document, int caretOffset) { + //TODO, look if cache is useful and possible to iplemennt, see issue #221000 + DocumentContext context = new DocumentContext(document); + + context.reset(caretOffset); + + return context; + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/Utils.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/Utils.java new file mode 100644 index 000000000000..bcb542529a51 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/completion/Utils.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.jakarta.web.beans.completion; + +import javax.swing.text.Document; +import org.netbeans.api.java.project.JavaProjectConstants; +import org.netbeans.api.java.source.ClasspathInfo; +import org.netbeans.api.java.source.JavaSource; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectUtils; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.modules.editor.NbEditorUtilities; +import org.openide.filesystems.FileObject; + +/** + * + * @author Marek Fukala + */ +public class Utils { + + public static String unquote(String quoted) { + if (quoted == null || quoted.length() <= 0) { + return quoted; + } + int start = 0; + int end = quoted.length(); + if (quoted.charAt(0) == '\"') { + start++; + } + if (quoted.charAt(end - 1) == '\"') { + end--; + } + if (start < end) { + return quoted.substring(start, end); + } else { + return ""; // NOI18N + } + } + public static JavaSource getJavaSource(Document doc) { + FileObject fileObject = NbEditorUtilities.getFileObject(doc); + if (fileObject == null) { + return null; + } + Project project = FileOwnerQuery.getOwner(fileObject); + if (project == null) { + return null; + } + // XXX this only works correctly with projects with a single sourcepath, + // but we don't plan to support another kind of projects anyway (what about Maven?). + // mkleint: Maven has just one sourceroot for java sources, the config files are placed under + // different source root though. JavaProjectConstants.SOURCES_TYPE_RESOURCES + SourceGroup[] sourceGroups = ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA); + for (SourceGroup sourceGroup : sourceGroups) { + return JavaSource.create(ClasspathInfo.create(sourceGroup.getRootFolder())); + } + return null; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/Bundle.properties b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/Bundle.properties new file mode 100644 index 000000000000..fffed14e0256 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/Bundle.properties @@ -0,0 +1,35 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +LBL_CreateCDIAnnotation=Create CDI Annotation + +LBL_FixCreateQualifier=Create Qualifier {0} in {1} +LBL_FixCreateQualifierDefaultPackage=Create Qualifier {0} in default package + +LBL_FixCreateInterceptor=Create Interceptor Binding {0} in {1} +LBL_FixCreateInterceptorDefaultPackage=Create Interceptor Binding {0} in default package + +# CDI Annotaitons +LBL_InjectionPoint=Injection point +LBL_DelegatePoint=Delegate injection point +LBL_DecoratedBean=Decorated managed bean +LBL_Event=CDI Event +LBL_Observer=CDI Observer +LBL_Intercepted=Intercepted element + +USG_CDI_CREATE_QUALIFIER_FIX=Created qualifier via fix for project "{0}". +USG_CDI_CREATE_IBINDING_FIX=Created interceptor binding via fix for project "{0}". \ No newline at end of file diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/CDIAnnotation.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/CDIAnnotation.java new file mode 100644 index 000000000000..dd2de36479e6 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/CDIAnnotation.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.hints; + +import org.openide.text.Annotation; +import org.openide.text.Line.Part; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class CDIAnnotation extends Annotation { + + public enum CDIAnnotaitonType { + INJECTION_POINT("org-netbeans-modules-jakarta-web-beans-annotations-injection-point"), + DELEGATE_POINT("org-netbeans-modules-jakarta-web-beans-annotations-delegate-point"), + DECORATED_BEAN("org-netbeans-modules-jakarta-web-beans-annotations-decorated-bean"), + EVENT("org-netbeans-modules-jakarta-web-beans-annotations-event"), + OBSERVER("org-netbeans-modules-jakarta-web-beans-annotations-observer"), + INTERCEPTED_ELEMENT("org-netbeans-modules-editor-annotations-intercepted"); + + private CDIAnnotaitonType( String type ){ + myType = type; + } + + @Override + public String toString(){ + return myType; + } + + private final String myType; + } + + CDIAnnotation( CDIAnnotaitonType type, Part part){ + myType = type; + myPart = part; + } + + /* (non-Javadoc) + * @see org.openide.text.Annotation#getAnnotationType() + */ + @Override + public String getAnnotationType() { + return myType.toString(); + } + + /* (non-Javadoc) + * @see org.openide.text.Annotation#getShortDescription() + */ + @Override + public String getShortDescription() { + switch (myType) { + case INJECTION_POINT: + return NbBundle.getMessage(CDIAnnotation.class, "LBL_InjectionPoint"); //NOI18N + case DELEGATE_POINT: + return NbBundle.getMessage(CDIAnnotation.class, "LBL_DelegatePoint"); //NOI18N + case DECORATED_BEAN: + return NbBundle.getMessage(CDIAnnotation.class, "LBL_DecoratedBean"); //NOI18N + case EVENT: + return NbBundle.getMessage(CDIAnnotation.class, "LBL_Event"); //NOI18N + case OBSERVER: + return NbBundle.getMessage(CDIAnnotation.class, "LBL_Observer"); //NOI18N + case INTERCEPTED_ELEMENT: + return NbBundle.getMessage(CDIAnnotation.class, "LBL_Intercepted"); //NOI18N + default: + assert false; + return null; + } + } + + public Part getPart(){ + return myPart; + } + + + private CDIAnnotaitonType myType; + private Part myPart; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/CreateAnnotationFix.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/CreateAnnotationFix.java new file mode 100644 index 000000000000..00178f6ef58b --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/CreateAnnotationFix.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.hints; + +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.api.java.source.ClasspathInfo.PathKind; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.modules.jakarta.web.beans.CdiUtil; +import org.netbeans.spi.editor.hints.ChangeInfo; +import org.netbeans.spi.editor.hints.Fix; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.loaders.DataFolder; +import org.openide.loaders.DataObject; + + +/** + * @author ads + * + */ +abstract class CreateAnnotationFix implements Fix { + + CreateAnnotationFix(CompilationInfo compilationInfo, String name , + String packageName , FileObject fileObject) + { + myInfo = compilationInfo; + myName = name; + myPackage = packageName; + myFileObject = fileObject; + + } + + /* (non-Javadoc) + * @see org.netbeans.spi.editor.hints.Fix#implement() + */ + @Override + public ChangeInfo implement() throws Exception { + FileObject template = FileUtil.getConfigFile(getTemplate()); + FileObject target; + + FileObject root = myInfo.getClasspathInfo() + .getClassPath(PathKind.SOURCE) + .findOwnerRoot(myInfo.getFileObject()); + FileObject pakage = FileUtil.createFolder(root, getPackage().replace('.', '/')); + + DataObject templateDO = DataObject.find(template); + DataObject od = templateDO.createFromTemplate( + DataFolder.findFolder(pakage), getName()); + + target = od.getPrimaryFile(); + + /*JavaSource javaSource = JavaSource.forFileObject(target); + ModificationResult diff = javaSource. + runModificationTask(new Task() { + public void run(final WorkingCopy working) throws IOException { + working.toPhase(Phase.RESOLVED); + + TreeMaker make = working.getTreeMaker(); + CompilationUnitTree cut = working.getCompilationUnit(); + ExpressionTree pack = cut.getPackageName() ; + ClassTree source = (ClassTree) cut.getTypeDecls().get(0); + + ModifiersTree modifiers = make.Modifiers(EnumSet.of(Modifier.PUBLIC)); + + ClassTree targetTree = (ClassTree)(new TreePath( + new TreePath(cut), source)).getLeaf(); + ClassTree annotationTree = make.AnnotationType(modifiers, + targetTree.getSimpleName(), targetTree.getMembers()); + + working.rewrite(cut, make.CompilationUnit(pack, cut.getImports(), + Collections.singletonList(annotationTree), cut.getSourceFile())); + } + }); + diff.commit();*/ + Project project = FileOwnerQuery.getOwner( myInfo.getFileObject() ); + if ( project != null ){ + CdiUtil logger = project.getLookup().lookup(CdiUtil.class); + if ( logger!= null ){ + logger.log(getUsageLogMessage(), getClass(), + new Object[]{project.getClass().getName()}); + } + } + return new ChangeInfo(target, null, null); + } + + protected abstract String getTemplate(); + + protected abstract String getUsageLogMessage(); + + protected String getName(){ + return myName; + } + + protected String getPackage(){ + return myPackage; + } + + private CompilationInfo myInfo; + private String myName; + private String myPackage; + private FileObject myFileObject; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/CreateInterceptorBinding.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/CreateInterceptorBinding.java new file mode 100644 index 000000000000..24d55e79ad84 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/CreateInterceptorBinding.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.hints; + +import org.netbeans.api.java.source.CompilationInfo; +import org.openide.filesystems.FileObject; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +final class CreateInterceptorBinding extends CreateAnnotationFix { + + CreateInterceptorBinding( CompilationInfo compilationInfo, String name, + String packageName, FileObject fileObject ) + { + super(compilationInfo, name, packageName, fileObject); + } + + /* (non-Javadoc) + * @see org.netbeans.spi.editor.hints.Fix#getText() + */ + @Override + public String getText() { + if ( getPackage() == null || getPackage().length() == 0 ){ + return NbBundle.getMessage(CreateQualifierFix.class, + "LBL_FixCreateInterceptorDefaultPackage"); + } + return NbBundle.getMessage(CreateQualifierFix.class, + "LBL_FixCreateInterceptor" , getName() , getPackage() ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.hints.CreateAnnotationFix#getUsageLogMessage() + */ + @Override + protected String getUsageLogMessage() { + return "USG_CDI_CREATE_IBINDING_FIX"; // NOI18N + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.hints.CreateAnnotationFix#getTemplate() + */ + @Override + protected String getTemplate() { + return "Templates/CDI/Interceptor.java"; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/CreateQualifier.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/CreateQualifier.java new file mode 100644 index 000000000000..aaad535473a4 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/CreateQualifier.java @@ -0,0 +1,417 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.hints; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; + +import org.netbeans.api.editor.EditorRegistry; +import org.netbeans.api.j2ee.core.Profile; +import org.netbeans.api.java.lexer.JavaTokenId; +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.SourceUtils; +import org.netbeans.api.java.source.TreeUtilities; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenHierarchy; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.modules.java.hints.spi.ErrorRule; +import org.netbeans.modules.editor.NbEditorUtilities; +import org.netbeans.modules.web.api.webmodule.WebModule; +import org.netbeans.modules.jakarta.web.beans.navigation.actions.WebBeansActionHelper; +import org.netbeans.spi.editor.hints.Fix; +import org.openide.filesystems.FileObject; +import org.openide.util.NbBundle; + +import com.sun.source.tree.Tree; +import com.sun.source.tree.Tree.Kind; +import com.sun.source.util.TreePath; + + +/** + * @author ads + * + */ +public class CreateQualifier implements ErrorRule { + + private static final String INJECT_ANNOTATION = + "jakarta.inject.Inject"; // NOI18N + + private static final String DISPOSES_ANNOTATION = + "jakarta.enterprise.inject.Disposes"; // NOI18N + + private static final String OBSERVES_ANNOTATION = + "jakarta.enterprise.event.Observes"; // NOI18N + + private static final String PRODUCER_ANNOTATION = + "jakarta.enterprise.inject.Produces"; // NOI18N + + private static final String INTERCEPTOR_ANNOTATION = + "jakarta.interceptor.Interceptor"; // NOI18N + + + /* (non-Javadoc) + * @see org.netbeans.modules.java.hints.spi.Rule#getId() + */ + @Override + public String getId() { + return CreateQualifier.class.getName(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.java.hints.spi.Rule#getDisplayName() + */ + @Override + public String getDisplayName() { + return NbBundle.getMessage(CreateQualifier.class, "LBL_CreateCDIAnnotation"); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.java.hints.spi.Rule#cancel() + */ + @Override + public void cancel() { + } + + /* (non-Javadoc) + * @see org.netbeans.modules.java.hints.spi.ErrorRule#getCodes() + */ + @Override + public Set getCodes() { + return new HashSet(Arrays.asList("compiler.err.cant.resolve.location", + "compiler.err.cant.resolve.location.args", + "compiler.err.cant.apply.symbol", "compiler.err.cant.resolve", + "compiler.err.cant.resolve.args")); // NOI18N + } + + /* (non-Javadoc) + * @see org.netbeans.modules.java.hints.spi.ErrorRule#run(org.netbeans.api.java.source.CompilationInfo, java.lang.String, int, org.netbeans.modules.java.hints.spi.TreePath, org.netbeans.modules.java.hints.spi.ErrorRule.Data) + */ + @Override + public List run( CompilationInfo compilationInfo, + String diagnosticKey, int offset, TreePath treePath, + org.netbeans.modules.java.hints.spi.ErrorRule.Data data ) + { + try { + return analyze(compilationInfo, offset); + } catch (IOException e) { + Logger.getLogger(CreateQualifier.class.getName()). + log(Level.SEVERE, null, e); + return null; + } catch (ClassCastException e) { + Logger.getLogger(CreateQualifier.class.getName()). + log(Level.FINE, null, e); + return null; + } + } + + protected List analyze( CompilationInfo compilationInfo, int offset ) + throws IOException + { + TreePath errorPath = findUnresolvedElement(compilationInfo, offset); + if ( !checkProject(compilationInfo) || errorPath == null) { + return Collections.emptyList(); + } + + if (compilationInfo.getElements().getTypeElement("java.lang.Object") == null) { // NOI18N + // broken java platform + return Collections.emptyList(); + } + + Element element = compilationInfo.getTrees().getElement(errorPath); + if ( element == null || element.getSimpleName() == null || + errorPath.getLeaf().getKind() != Kind.IDENTIFIER ) + { + return Collections.emptyList(); + } + + TreePath parentPath = errorPath.getParentPath(); + if ( parentPath.getLeaf().getKind() != Kind.ANNOTATION ){ + return Collections.emptyList(); + } + Element annotation = compilationInfo.getTrees().getElement(parentPath); + TreePath path = parentPath; + while (path != null ){ + Tree leaf = path.getLeaf(); + Kind leafKind = leaf.getKind(); + if ( TreeUtilities.CLASS_TREE_KINDS.contains(leafKind) ){ + Element clazz = compilationInfo.getTrees().getElement(path); + if ( clazz != null && clazz.getKind() == ElementKind.CLASS ) + { + return analyzeClass( compilationInfo , (TypeElement)clazz , + annotation ); + } + } + else if ( leafKind == Kind.VARIABLE){ + Element var = compilationInfo.getTrees().getElement(path); + if ( var == null ){ + return null; + } + Element parent = var.getEnclosingElement(); + if ( var.getKind() == ElementKind.FIELD && + (parent instanceof TypeElement)) + { + return analyzeField( compilationInfo , var , annotation , + (TypeElement)parent); + } + } + else if ( leafKind == Kind.METHOD ){ + Element method = compilationInfo.getTrees().getElement(path); + if ( method != null && method.getKind() == ElementKind.METHOD){ + return analyzeMethodParameter( compilationInfo , + (ExecutableElement)method , annotation ); + } + } + path = path.getParentPath(); + } + + return null; + } + + private List analyzeMethodParameter( CompilationInfo compilationInfo, + ExecutableElement method, Element annotation ) + { + Element parent = method.getEnclosingElement(); + if ( !(parent instanceof TypeElement)){ + return Collections.emptyList(); + } + List parameters = method.getParameters(); + List allAnnotationMirrors = + compilationInfo.getElements().getAllAnnotationMirrors(method); + for (AnnotationMirror annotationMirror : allAnnotationMirrors) { + TypeElement annotationElement = (TypeElement)annotationMirror. + getAnnotationType().asElement(); + if ( annotationElement != null && annotationElement.getQualifiedName(). + contentEquals(INJECT_ANNOTATION) || + annotationElement.getQualifiedName(). + contentEquals(PRODUCER_ANNOTATION)) + { + + return createQualifierFix(compilationInfo, annotation, parent); + } + + } + boolean hasDisposesObserves = false; + boolean parameterHasAnnotation = false; + for (VariableElement variableElement : parameters) { + allAnnotationMirrors = + compilationInfo.getElements().getAllAnnotationMirrors(variableElement); + for (AnnotationMirror annotationMirror : allAnnotationMirrors) { + TypeElement annotationElement = (TypeElement)annotationMirror. + getAnnotationType().asElement(); + if ( annotationElement != null && annotationElement.getQualifiedName(). + contentEquals( OBSERVES_ANNOTATION ) || + annotationElement.getQualifiedName(). + contentEquals( DISPOSES_ANNOTATION )) + { + hasDisposesObserves= true; + } + else if ( annotationElement != null && + annotationElement.equals( annotation )) + { + parameterHasAnnotation = true; + } + } + } + if ( parameterHasAnnotation && hasDisposesObserves ){ + return createQualifierFix(compilationInfo, annotation, parent); + } + return Collections.emptyList(); + } + + + private List createQualifierFix( CompilationInfo compilationInfo, + Element annotation, Element classElement ) + { + PackageElement packageElement = compilationInfo.getElements() + .getPackageOf(classElement); + FileObject targetFile = SourceUtils.getFile( + ElementHandle.create(classElement), + compilationInfo.getClasspathInfo()); + return Collections. singletonList(new CreateQualifierFix( + compilationInfo, annotation.getSimpleName().toString(), + packageElement.getQualifiedName().toString(), + targetFile)); + } + + private List createInterceptorFix( CompilationInfo compilationInfo, + Element annotation, Element classElement ) + { + PackageElement packageElement = compilationInfo.getElements() + .getPackageOf(classElement); + FileObject targetFile = SourceUtils.getFile( + ElementHandle.create(classElement), + compilationInfo.getClasspathInfo()); + return Collections. singletonList(new CreateInterceptorBinding( + compilationInfo, annotation.getSimpleName().toString(), + packageElement.getQualifiedName().toString(), + targetFile)); + } + + private List analyzeField( CompilationInfo compilationInfo, + Element var, Element annotation , TypeElement parent ) + { + List allAnnotationMirrors = + compilationInfo.getElements().getAllAnnotationMirrors(var); + boolean isInjectionPoint = false; + boolean hasRequiredAnnotation = false; + for (AnnotationMirror annotationMirror : allAnnotationMirrors) { + Element annotationElement = annotationMirror.getAnnotationType(). + asElement(); + TypeElement annotationTypeElement = (TypeElement)annotationElement; + if ( annotationElement.equals( annotation)) + { + hasRequiredAnnotation = true; + } + else if ( annotationTypeElement!= null && + annotationTypeElement.getQualifiedName().contentEquals( + INJECT_ANNOTATION) || + annotationTypeElement.getQualifiedName(). + contentEquals(PRODUCER_ANNOTATION)) + { + isInjectionPoint = true; + } + } + if ( hasRequiredAnnotation && isInjectionPoint ){ + return createQualifierFix(compilationInfo, annotation, parent); + } + return Collections.emptyList(); + } + + private List analyzeClass( CompilationInfo compilationInfo, + TypeElement clazz, Element annotation ) + { + List allAnnotationMirrors = + compilationInfo.getElements().getAllAnnotationMirrors(clazz); + boolean isInterceptor = false; + boolean hasAnnotation = false; + for (AnnotationMirror annotationMirror : allAnnotationMirrors) { + Element annotationElement = annotationMirror.getAnnotationType().asElement(); + if ( annotationElement!= null && annotationElement.equals( annotation)){ + hasAnnotation = true; + } + if ( annotationElement instanceof TypeElement && + ((TypeElement)annotationElement).getQualifiedName(). + contentEquals(INTERCEPTOR_ANNOTATION)) + { + isInterceptor = true; + } + } + if ( !hasAnnotation ){ + return Collections.emptyList(); + } + if ( isInterceptor ){ + return createInterceptorFix(compilationInfo, annotation, clazz); + } + else { + return createQualifierFix(compilationInfo, annotation, clazz); + } + } + + private boolean checkProject(CompilationInfo info){ + final FileObject fileObject = info.getFileObject(); + return WebBeansActionHelper.isEnabled( fileObject ); + } + + private TreePath findUnresolvedElement(CompilationInfo info, int offset) + throws IOException + { + int[] span = findUnresolvedElementSpan(info, offset); + + if (span != null) { + return info.getTreeUtilities().pathFor(span[0] + 1); + } else { + return null; + } + } + + private int[] findUnresolvedElementSpan(CompilationInfo info, int offset) + throws IOException + { + Token t = findUnresolvedElementToken(info, offset); + + if (t != null) { + return new int[] { + t.offset(null), + t.offset(null) + t.length() + }; + } + + return null; + } + + private Token findUnresolvedElementToken(CompilationInfo info, int offset) + throws IOException + { + TokenHierarchy th = info.getTokenHierarchy(); + TokenSequence ts = th.tokenSequence(JavaTokenId.language()); + + if (ts == null) { + return null; + } + + ts.move(offset); + if (ts.moveNext()) { + Token t = ts.token(); + + if (t.id() == JavaTokenId.DOT) { + ts.moveNext(); + t = ts.token(); + } else { + if (t.id() == JavaTokenId.LT) { + ts.moveNext(); + t = ts.token(); + } else { + if (t.id() == JavaTokenId.NEW || t.id() == JavaTokenId.WHITESPACE) { + boolean cont = ts.moveNext(); + + while (cont && ts.token().id() == JavaTokenId.WHITESPACE) { + cont = ts.moveNext(); + } + + if (!cont) + return null; + + t = ts.token(); + } + } + } + + if (t.id() == JavaTokenId.IDENTIFIER) { + return ts.offsetToken(); + } + } + return null; + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/CreateQualifierFix.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/CreateQualifierFix.java new file mode 100644 index 000000000000..916d79d71620 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/CreateQualifierFix.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.hints; + +import org.netbeans.api.java.source.CompilationInfo; +import org.openide.filesystems.FileObject; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +final class CreateQualifierFix extends CreateAnnotationFix { + + CreateQualifierFix( CompilationInfo compilationInfo, String name , + String packageName , FileObject fileObject) + { + super(compilationInfo, name, packageName, fileObject); + } + + /* (non-Javadoc) + * @see org.netbeans.spi.editor.hints.Fix#getText() + */ + @Override + public String getText() { + if ( getPackage() == null || getPackage().length() == 0 ){ + return NbBundle.getMessage(CreateQualifierFix.class, + "LBL_FixCreateQualifierDefaultPackage"); // NOI18N + } + return NbBundle.getMessage(CreateQualifierFix.class, + "LBL_FixCreateQualifier" , getName() , getPackage() ); // NOI18N + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.hints.CreateAnnotationFix#getUsageLogMessage() + */ + @Override + protected String getUsageLogMessage() { + return "USG_CDI_CREATE_QUALIFIER_FIX"; // NOI18N + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.hints.CreateAnnotationFix#getTemplate() + */ + @Override + protected String getTemplate() { + return "Templates/CDI/Qualifier.java"; // NOI18N + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/EditorAnnotationsHelper.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/EditorAnnotationsHelper.java new file mode 100644 index 000000000000..d10d925cd0c9 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/hints/EditorAnnotationsHelper.java @@ -0,0 +1,252 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.hints; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.swing.text.Document; +import javax.swing.text.StyledDocument; + +import org.netbeans.modules.editor.NbEditorUtilities; +import org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult; +import org.netbeans.modules.jakarta.web.beans.analysis.CdiEditorAnalysisFactory; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result; +import org.netbeans.modules.jakarta.web.beans.hints.CDIAnnotation.CDIAnnotaitonType; +import org.openide.cookies.EditorCookie; +import org.openide.filesystems.FileObject; +import org.openide.loaders.DataObject; +import org.openide.text.Line; +import org.openide.text.Line.Part; +import org.openide.text.NbDocument; +import org.openide.util.RequestProcessor; + +import com.sun.source.tree.Tree; + + +/** + * @author ads + * + */ +public final class EditorAnnotationsHelper implements PropertyChangeListener { + + private static ConcurrentHashMap HELPERS + = new ConcurrentHashMap(); + + private static final RequestProcessor PROCESSOR = new RequestProcessor( + EditorAnnotationsHelper.class.getName(), 1, false, false); + + private EditorAnnotationsHelper( DataObject dataObject , + EditorCookie.Observable observable ) + { + myDataObject = dataObject; + myObservable = observable; + myModelAnnotations = new AtomicReference>( + Collections.emptyList()); + myAnnotations = new AtomicReference>( + Collections.emptyList()); + + observable.addPropertyChangeListener(this ); + } + + /* (non-Javadoc) + * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent) + */ + @Override + public void propertyChange( PropertyChangeEvent evt ) { + if (EditorCookie.Observable.PROP_OPENED_PANES.endsWith(evt.getPropertyName()) + || evt.getPropertyName() == null) + { + if (myObservable.getOpenedPanes() == null) { + myObservable.removePropertyChangeListener(this); + + Runnable runnable = new Runnable() { + + @Override + public void run() { + HELPERS.remove(myDataObject); + List annotations = myModelAnnotations.get(); + for (CDIAnnotation annotation : annotations) { + annotation.detach(); + } + annotations = myAnnotations.get(); + for( CDIAnnotation annotation : annotations ){ + annotation.detach(); + } + myModelAnnotations.set( Collections.emptyList()); + myAnnotations.set( Collections.emptyList()); + } + }; + PROCESSOR.submit(runnable); + } + } + } + + public static EditorAnnotationsHelper getInstance( CdiAnalysisResult result ){ + return getInstance( result.getInfo().getFileObject()); + } + + public static EditorAnnotationsHelper getInstance( FileObject fileObject ){ + try { + DataObject dataObject = DataObject.find(fileObject); + EditorAnnotationsHelper helper = HELPERS.get(dataObject); + + if (helper != null) { + return helper; + } + + EditorCookie.Observable observable = dataObject.getLookup().lookup( + EditorCookie.Observable.class); + + if (observable == null) { + return null; + } + + helper = new EditorAnnotationsHelper( dataObject , observable ); + HELPERS.put(dataObject, helper ); + + return helper; + } catch (IOException ex) { + Logger.getLogger( EditorAnnotationsHelper.class.getName() ). + log(Level.INFO, null, ex); + return null; + } + } + + public void addInjectionPoint( CdiAnalysisResult result, VariableElement element ) + { + addAnnotation(result, element, CDIAnnotaitonType.INJECTION_POINT ); + } + + public void addDelegate( CdiAnalysisResult result , VariableElement element ) { + addAnnotation(result, element, CDIAnnotaitonType.DELEGATE_POINT ); + } + + public void addEventInjectionPoint( Result result, VariableElement element ) + { + addAnnotation(result, element, CDIAnnotaitonType.EVENT ); + } + + public void addObserver( CdiAnalysisResult result, ExecutableElement element ) + { + addAnnotation(result, element, CDIAnnotaitonType.OBSERVER ); + } + + public void addInterceptedBean(CdiAnalysisResult result , TypeElement element ) { + addAnnotation(result, element, CDIAnnotaitonType.INTERCEPTED_ELEMENT ); + } + + public void addInterceptedMethod( Result result, ExecutableElement element ) + { + addAnnotation(result, element, CDIAnnotaitonType.INTERCEPTED_ELEMENT ); + } + + public void addDecoratedBean( Result result, TypeElement element ) { + addAnnotation(result, element, CDIAnnotaitonType.DECORATED_BEAN ); + } + + public void publish( final CdiAnalysisResult result ) { + Runnable runnable = new Runnable() { + + @Override + public void run() { + AtomicReference> ref ; + if ( result instanceof Result ){ + ref = myAnnotations; + } + else if ( result.getClass() == CdiAnalysisResult.class ){ + ref = myModelAnnotations; + } + else { + ref = null; + assert false; + } + List annotations = ref.get(); + for (CDIAnnotation annotation : annotations) { + annotation.detach(); + } + List collected = result.getAnnotations(); + + for (CDIAnnotation annotation : collected) { + annotation.attach( annotation.getPart() ); + } + ref.set(collected); + } + }; + PROCESSOR.submit(runnable); + } + + public List getAnnotations(){ + List modelAnnotations = myModelAnnotations.get(); + List annotations = myAnnotations.get(); + List result = new ArrayList( + modelAnnotations.size() +annotations.size()); + result.addAll( modelAnnotations); + result.addAll( annotations ); + return result; + } + + private void addAnnotation( CdiAnalysisResult result, Element element , + CDIAnnotaitonType type ) + { + if ( element == null ){ + return; + } + Tree var = result.getInfo().getTrees().getTree( element ); + if ( var == null ){ + return; + } + List position = CdiEditorAnalysisFactory.getElementPosition( + result.getInfo(), var ); + Document document; + try { + document = result.getInfo().getDocument(); + if ( !( document instanceof StyledDocument) ){ + return; + } + } + catch (IOException e) { + return; + } + int start = position.get(0); + Line line = NbEditorUtilities.getLine( document , start, false); + Part part = line.createPart( NbDocument.findLineColumn((StyledDocument) document, + start), position.get( 1 ) -start); + result.addAnnotation( new CDIAnnotation( type, part)); + } + + private DataObject myDataObject; + private EditorCookie.Observable myObservable; + private AtomicReference> myModelAnnotations; + private AtomicReference> myAnnotations; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/AbstractAssignabilityChecker.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/AbstractAssignabilityChecker.java new file mode 100644 index 000000000000..622bee3503a0 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/AbstractAssignabilityChecker.java @@ -0,0 +1,353 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ReferenceType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.WildcardType; +import javax.lang.model.util.Types; + + +/** + * @author ads + * + */ +abstract class AbstractAssignabilityChecker implements Checker { + + enum AssignabilityType { + PLAIN, // Assignability for typesafe resolution for bean types by the web beans spec + EVENT, // Assignability for observer/event resolution + DECORATOR // Assignability for decorator resolution + } + + static AbstractAssignabilityChecker get( AssignabilityType type) { + switch ( type ){ + case PLAIN : + return new AssignabilityChecker(); + case EVENT: + return new EventAssignabilityChecker(); + case DECORATOR : + return new DelegateAssignabilityChecker(); + default: + // no other types are handled + assert false; + return null; + } + } + + void init( ReferenceType varType, ReferenceType checkedType, + Element originalElement, WebBeansModelImplementation impl) + { + myVarType = varType; + myType = checkedType; + myImpl = impl; + myOriginalElement = originalElement; + } + + void init( ReferenceType varType, ReferenceType checkedType, + WebBeansModelImplementation impl) + { + init( varType , checkedType , null, impl ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.Checker#check() + */ + @Override + public boolean check(){ + boolean check = checkAssignability( getVarType(), getType(), + myOriginalElement); + return check; + } + + public boolean checkAssignability( ReferenceType variableType , + ReferenceType refType , Element originalElement ) + { + boolean isDeclaredType = variableType instanceof DeclaredType && + variableType.getKind()!=TypeKind.ERROR ; + if ( !isDeclaredType ){ + return checkParameter(refType, variableType); + } + Element variableElement = ((DeclaredType)variableType).asElement(); + if ( !( variableElement instanceof TypeElement ) ){ + return false; + } + + if ( !( refType instanceof DeclaredType ) || + refType.getKind() == TypeKind.ERROR) + { + return false; + } + DeclaredType type = (DeclaredType)refType; + + Element refElement = getImplementation().getHelper(). + getCompilationController().getTypes().asElement( type ); + if ( !( refElement instanceof TypeElement ) ){ + return false; + } + + if ( !hasBeanType( originalElement, variableType) ){ + return false; + } + + /* + * Find ancestor of refType with the same raw type. + * Raw types should be identical for parameterized type by the spec. + * It means that inheritance by parameterized types are not allowed. + */ + Types types = getImplementation().getHelper().getCompilationController().getTypes(); + if ( !types.isSameType( types.erasure( variableType ) , types.erasure(type)) ){ + TypeMirror ancestor = getAncestor(type ,types.erasure( variableType ) , + types ); + // no appropriate type + if ( !(ancestor instanceof DeclaredType)){ + return false; + } + type = (DeclaredType) ancestor; + } + + List typeArguments = type.getTypeArguments(); + + TypeElement objectElement = getImplementation().getHelper(). + getCompilationController().getElements().getTypeElement( + Object.class.getCanonicalName()); + + List varTypeArguments = ((DeclaredType)variableType). + getTypeArguments(); + if ( varTypeArguments.size() == 0 || types.isSameType( variableType, + types.erasure( variableType ) )) + /* + * I'm not sure how to detect variable declaration with generic type: + * - it is unclear how many arguments has such type as result + * - probably such type could have typevar argument ( the same as generic + * declaration ). In the letter case this type mirror should be the same + * as generic declaration type mirror. So I put here comparison with + * type after erasure. + */ + { + return handleRequiredRawType(types, typeArguments, objectElement); + } + if ( typeArguments.size() == 0 || types.isSameType( type, + types.erasure( type ) )) + { + return handleBeanRawType(types, varTypeArguments, objectElement); + } + if ( varTypeArguments.size() != typeArguments.size() ){ + /* + * This should not happen because raw types are checked before. + * So generic type is the same. As consequence size of parameters + * and arguments should be the same. + */ + return false; + } + for ( int i=0; i< varTypeArguments.size() ; i++ ){ + TypeMirror argType = typeArguments.get(i); + if ( !checkParameter( argType , varTypeArguments.get(i) ) ){ + return false; + } + } + return true; + } + + protected abstract boolean handleBeanRawType( Types types, + List varTypeArguments, TypeElement objectElement ); + + protected abstract boolean hasBeanType(Element element,ReferenceType variableType); + + protected abstract boolean handleRequiredRawType( Types types, + List typeArguments, TypeElement objectElement ); + + public boolean checkAssignability( ReferenceType variableType , + ReferenceType refType ) + { + return checkAssignability(variableType, refType, null); + } + + protected boolean checkParameter( TypeMirror argType, TypeMirror varTypeArg ) + { + if ( argType == null || varTypeArg == null ){ + return false; + } + Types types = getImplementation().getHelper().getCompilationController(). + getTypes(); + + /* + * Implementation of spec item : + * the required type parameter and the bean type parameter are actual + * types with identical raw type, and, if the type is + * parameterized, the bean type parameter is assignable to the required + * type parameter according to these rules + */ + if ( argType.getKind()!= TypeKind.TYPEVAR && + varTypeArg.getKind()!= TypeKind.TYPEVAR && + (argType instanceof ReferenceType) && + (varTypeArg instanceof ReferenceType) ) + { + return checkIsAssignable(getImplementation().getHelper(). + getCompilationController().getTypes(), argType, varTypeArg); + } + + if ( varTypeArg.getKind() == TypeKind.WILDCARD ){ + return handleWildCard(argType, (WildcardType)varTypeArg, types); + } + + if ( argType.getKind() == TypeKind.TYPEVAR && + varTypeArg.getKind() == TypeKind.TYPEVAR) + { + return handleBothTypeVars(argType, varTypeArg, types); + } + + if (varTypeArg.getKind() != TypeKind.TYPEVAR + && argType.getKind() == TypeKind.TYPEVAR) + { + return handleBeanTypeVar(argType, varTypeArg, types); + } + if (argType.getKind() != TypeKind.TYPEVAR + && varTypeArg.getKind() == TypeKind.TYPEVAR) + { + return handleRequiredTypeVar(argType, varTypeArg, types); + } + + return false; + } + + protected abstract boolean handleRequiredTypeVar( TypeMirror argType, + TypeMirror varTypeArg, Types types ); + + protected abstract boolean handleBeanTypeVar( TypeMirror argType, TypeMirror varTypeArg, + Types types ); + + protected abstract boolean handleBothTypeVars( TypeMirror argType, + TypeMirror varTypeArg, Types types ); + + protected boolean handleWildCard( TypeMirror argType, WildcardType varTypeArg, + Types types ) + { + TypeMirror upperBound = varTypeArg.getExtendsBound(); + TypeMirror lowerBound = varTypeArg.getSuperBound(); + + if ( argType instanceof ReferenceType && + argType.getKind()!=TypeKind.TYPEVAR) + { + return handleWildCardActualType(argType, types, upperBound, + lowerBound); + } + + if ( argType.getKind() == TypeKind.TYPEVAR ){ + return handleWildCardTypeVar(argType, types, upperBound, lowerBound); + } + + return false; + } + + protected boolean handleWildCardActualType( TypeMirror argType, Types types, + TypeMirror upperBound, TypeMirror lowerBound ){ + /* + * Implementation of spec item : the required type parameter is + * a wildcard, the bean type parameter is an actual type and the + * actual type is assignable to the upper bound, if any, of the + * wildcard and assignable from the lower bound, if any, of the + * wildcard + */ + if ( upperBound == null || upperBound.getKind() == TypeKind.NULL){ + if ( lowerBound == null || lowerBound.getKind() == TypeKind.NULL){ + return true; + } + else { + return checkIsAssignable(types, lowerBound, argType); + } + } + else { + if ( lowerBound == null || lowerBound.getKind() == TypeKind.NULL){ + return checkIsAssignable(types, argType, upperBound); + } + else { + return checkIsAssignable(types, argType, upperBound) && + checkIsAssignable(types, lowerBound, argType); + } + } + } + + protected abstract boolean handleWildCardTypeVar( TypeMirror argType, Types types, + TypeMirror upperBound, TypeMirror lowerBound ); + + + protected boolean checkIsAssignable( Types types, TypeMirror from, + TypeMirror to ) + { + if ( isAssignable(from, to, types)){ + return true; + } + else if( to instanceof ReferenceType && from instanceof ReferenceType ) + { + return checkAssignability( (ReferenceType)to, + (ReferenceType)from); + } + else { + return false; + } + } + + protected boolean isAssignable( TypeMirror from, TypeMirror to, Types types ) + { + Element element = types.asElement(to); + boolean isGeneric = (element instanceof TypeElement) + && ((TypeElement) element).getTypeParameters().size() != 0; + return !isGeneric && ( to instanceof DeclaredType ); + } + + private TypeMirror getAncestor( TypeMirror subject , TypeMirror rawType , + Types types) + { + List directSupertypes = types.directSupertypes(subject); + for (TypeMirror typeMirror : directSupertypes) { + if ( types.isSameType(types.erasure( typeMirror), rawType)){ + return typeMirror; + } + TypeMirror found = getAncestor(typeMirror, rawType, types); + if ( found != null ){ + return found; + } + } + return null; + } + + protected ReferenceType getVarType(){ + return myVarType; + } + + protected WebBeansModelImplementation getImplementation(){ + return myImpl; + } + + protected ReferenceType getType(){ + return myType; + } + + private Element myOriginalElement; + private ReferenceType myVarType; + private WebBeansModelImplementation myImpl; + private ReferenceType myType; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/AbstractObjectProvider.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/AbstractObjectProvider.java new file mode 100644 index 000000000000..3364ab786af3 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/AbstractObjectProvider.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.Collections; +import java.util.EnumSet; +import java.util.LinkedList; +import java.util.List; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationHandler; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.ObjectProvider; + + +/** + * @author ads + * + */ +abstract class AbstractObjectProvider + implements ObjectProvider +{ + + AbstractObjectProvider(String annotation , AnnotationModelHelper helper) + { + myHelper = helper; + myAnnotationName = annotation; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.j2ee.metadata.model.api.support.annotation.ObjectProvider#createInitialObjects() + */ + @Override + public List createInitialObjects() throws InterruptedException { + final List result = new LinkedList(); + getHelper().getAnnotationScanner().findAnnotations( + getAnnotation(), + EnumSet.of(ElementKind.CLASS, ElementKind.INTERFACE), + new AnnotationHandler() { + @Override + public void handleAnnotation(TypeElement type, + Element element, AnnotationMirror annotation) + { + result.add(createTypeElement(type)); + } + }); + return result; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.j2ee.metadata.model.api.support.annotation.ObjectProvider#createObjects(javax.lang.model.element.TypeElement) + */ + @Override + public List createObjects( TypeElement type ) { + if ((type.getKind() == ElementKind.CLASS || type.getKind() == ElementKind.INTERFACE) + && getHelper().hasAnnotation(type.getAnnotationMirrors(), + getAnnotation())) + { + return Collections.singletonList(createTypeElement(type)); + } + return Collections.emptyList(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.j2ee.metadata.model.api.support.annotation.ObjectProvider#modifyObjects(javax.lang.model.element.TypeElement, java.util.List) + */ + @Override + public boolean modifyObjects( TypeElement type, List objects ) { + assert objects.size() ==1; + T object = objects.get(0); + assert object!= null; + if ( ! object.refresh(type)){ + objects.remove(0); + return true; + } + return false; + } + + protected abstract T createTypeElement( TypeElement element ); + + public static List getAnnotatedMembers( final String annotationName, + final AnnotationModelHelper helper ) + { + final List result = new LinkedList(); + try { + helper.getAnnotationScanner().findAnnotations( + annotationName, + EnumSet.of(ElementKind.FIELD, ElementKind.METHOD), + new AnnotationHandler() { + @Override + public void handleAnnotation(TypeElement type, + Element element, AnnotationMirror annotation) + { + result.add(element); + } + }); + } + catch (InterruptedException e) { + FieldInjectionPointLogic.LOGGER.warning("Finding annotation "+ + annotationName+" was interrupted"); // NOI18N + } + return result; + } + + protected AnnotationModelHelper getHelper(){ + return myHelper; + } + + protected String getAnnotation(){ + return myAnnotationName; + } + + public static List getNamedMembers( AnnotationModelHelper helper ) + { + List namedMembers = getAnnotatedMembers( + FieldInjectionPointLogic.NAMED_QUALIFIER_ANNOTATION, helper); + return namedMembers; + } + + static interface Refreshable { + boolean refresh( TypeElement type ); + } + + private AnnotationModelHelper myHelper; + private String myAnnotationName; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/AnnotationObjectProvider.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/AnnotationObjectProvider.java new file mode 100644 index 000000000000..629dde14f2eb --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/AnnotationObjectProvider.java @@ -0,0 +1,474 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.lang.annotation.Inherited; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.ClassIndex.SearchKind; +import org.netbeans.api.java.source.ClassIndex.SearchScope; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationHandler; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationScanner; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.ObjectProvider; + + +/** + * This object provider cares about types that directly have annotations, + * types that inherit annotations ( they extends class or interface that + * directly have annotation and either + * - annotations is @Inherited + * - type specializes type with annotation ( each hierarchy step has @Specializes + * annotations ). + * + * So result object ( type ) could not have directly annotation under subject and also + * there could be objects ( types ) which don't have even inherited annotation. + * ( but hey have parents with this annotation and they specializes this parent ). + * @author ads + * + */ +public class AnnotationObjectProvider implements ObjectProvider { + + private static final String SPECILIZES_ANNOTATION = + "jakarta.enterprise.inject.Specializes"; // NOI18N + + static final Logger LOGGER = Logger.getLogger( + AnnotationObjectProvider.class.getName()); + + AnnotationObjectProvider( AnnotationModelHelper helper , String annotation) { + myHelper = helper; + myAnnotationName = annotation; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.j2ee.metadata.model.api.support.annotation.ObjectProvider#createInitialObjects() + */ + @Override + public List createInitialObjects() throws InterruptedException { + final List result = new LinkedList(); + final Set set = new HashSet(); + getHelper().getAnnotationScanner().findAnnotations(getAnnotationName(), + AnnotationScanner.TYPE_KINDS, + new AnnotationHandler() { + @Override + public void handleAnnotation(TypeElement type, + Element element, AnnotationMirror annotation) + { + if ( !set.contains( type )){ + result.add( new BindingQualifier( getHelper(), type , + getAnnotationName())); + } + set.add( type ); + if ( !getHelper().hasAnnotation( annotation. + getAnnotationType().asElement(). + getAnnotationMirrors(), + Inherited.class.getCanonicalName())) + { + /* + * if annotation is inherited then method + * findAnnotations() + * method will return types with this annotation. + * Otherwise there could be implementors which + * specialize this type. + */ + collectSpecializedImplementors( type , set, result ); + } + } + + } ); + return new ArrayList( result ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.j2ee.metadata.model.api.support.annotation.ObjectProvider#createObjects(javax.lang.model.element.TypeElement) + */ + @Override + public List createObjects( TypeElement type ) { + final List result = new ArrayList(); + Map annotationsByType = + getHelper().getAnnotationsByType(getHelper().getCompilationController(). + getElements().getAllAnnotationMirrors( type )); + AnnotationMirror annotationMirror = annotationsByType.get( + getAnnotationName()); + if (annotationMirror != null ) { + result.add( new BindingQualifier(getHelper(), type, getAnnotationName())); + } + if ( annotationMirror == null || !getHelper().hasAnnotation( annotationMirror. + getAnnotationType().asElement(). + getAnnotationMirrors(), + Inherited.class.getCanonicalName())) + { + if ( checkSuper( type , getAnnotationName() , getHelper())!= null ){ + result.add( new BindingQualifier( getHelper(), type, getAnnotationName()) ); + } + } + return result; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.j2ee.metadata.model.api.support.annotation.ObjectProvider#modifyObjects(javax.lang.model.element.TypeElement, java.util.List) + */ + @Override + public boolean modifyObjects( TypeElement type, List bindings ) { + /* + * Type element couldn't have the same annotation twice. + * Provider based on single annotation ( its FQN ). + * So each type could have only one annotation at most. + */ + assert bindings.size() ==1; + BindingQualifier binding = bindings.get(0); + assert binding!= null; + if ( ! binding.refresh(type)){ + bindings.remove(0); + return true; + } + return false; + } + + static void visitSpecializes( TypeElement type, AnnotationModelHelper helper, + SpecializeVisitor visitor ) + { + if ( !hasSpecializes( type, helper )){ + return; + } + + TypeElement superClass = helper.getSuperclass(type); + if ( superClass != null ){ + if ( visitor.visit( superClass ) ){ + return; + } + visitSpecializes(superClass, helper, visitor); + } + + /* interfaces could not be injectables , but let's inspect them as possible + * injectables for notifying user about error if any. + */ + + List interfaces = type.getInterfaces(); + for (TypeMirror typeMirror : interfaces) { + Element el = helper.getCompilationController().getTypes(). + asElement(typeMirror); + if ( el instanceof TypeElement ){ + TypeElement interfaceElement = (TypeElement) el; + visitSpecializes( interfaceElement , helper , visitor ); + } + } + } + + static TypeElement checkSuper( TypeElement type , final String annotationName, + final AnnotationModelHelper helper ) + { + final TypeElement result[] = new TypeElement[1]; + SpecializeVisitor visitor = new SpecializeVisitor(){ + + @Override + public boolean visit( TypeElement element ) { + if ( FieldInjectionPointLogic.DEFAULT_QUALIFIER_ANNOTATION.equals( + annotationName)) + { + if ( checkSpecializedDefault( element, helper )){ + result[0] = element; + return true; + } + } + if ( hasAnnotation( element , annotationName, helper)){ + result[0] = element; + return true; + } + return false; + } + + @Override + public boolean visit( ExecutableElement element ) { + return false; + } + + }; + visitSpecializes(type, helper, visitor); + return result[0]; + } + + /* + * This method is called only for parent which are specialized. + * In this case @Default is not "inherited" by child from parents. + */ + static boolean checkSpecializedDefault( Element element , AnnotationModelHelper helper){ + return helper.hasAnnotation( helper.getCompilationController(). + getElements().getAllAnnotationMirrors(element), + WebBeansModelProviderImpl.DEFAULT_QUALIFIER_ANNOTATION); + } + + static boolean checkDefault( Element element , AnnotationModelHelper helper){ + Set qualifierNames = getQualifiers(element, helper , false ); + if ( qualifierNames.contains( + WebBeansModelProviderImpl.DEFAULT_QUALIFIER_ANNOTATION)) + { + return true; + } + qualifierNames.remove( ParameterInjectionPointLogic.NAMED_QUALIFIER_ANNOTATION); + qualifierNames.remove( ParameterInjectionPointLogic.ANY_QUALIFIER_ANNOTATION); + if ( qualifierNames.size() == 0 ){ + return true; + } + return false; + } + + static Set getQualifiers(Element element , + AnnotationModelHelper helper , boolean event ) + { + final Set result = new HashSet(); + AnnotationHandleStrategy strategy = new AnnotationHandleStrategy(){ + + @Override + public void handleAnnotation( AnnotationMirror annotationMirror , + TypeElement annotationElement) + { + result.add(annotationElement.getQualifiedName().toString()); + } + }; + findQualifiers(element, helper, event, strategy); + return result; + } + + static void findQualifiers(Element element , + AnnotationModelHelper helper , boolean event , + AnnotationHandleStrategy strategy ) + { + List allAnnotationMirrors = + helper.getCompilationController().getElements(). + getAllAnnotationMirrors( element ); + for (AnnotationMirror annotationMirror : allAnnotationMirrors) { + DeclaredType annotationType = annotationMirror + .getAnnotationType(); + if ( annotationType == null || annotationType.getKind() == TypeKind.ERROR){ + continue; + } + TypeElement annotationElement = (TypeElement) annotationType + .asElement(); + if (annotationElement!= null && isQualifier(annotationElement, + helper , event )) + { + strategy.handleAnnotation(annotationMirror , annotationElement ); + } + } + } + + static boolean isQualifier( TypeElement annotationElement , + AnnotationModelHelper helper, boolean event ) + { + QualifierChecker checker = QualifierChecker.get( event ); + checker.init(annotationElement, helper ); + return checker.check(); + } + + public static boolean hasSpecializes( Element element , + AnnotationModelHelper helper ) + { + return hasAnnotation(element , SPECILIZES_ANNOTATION , helper ); + } + + static boolean hasAnnotation( Element element, String annotation, + AnnotationModelHelper helper ) + { + List allAnnotationMirrors = + helper.getCompilationController().getElements(). + getAllAnnotationMirrors(element); + return helper.hasAnnotation(allAnnotationMirrors, + annotation ); + } + + private String getAnnotationName(){ + return myAnnotationName; + } + + private AnnotationModelHelper getHelper(){ + return myHelper; + } + + private void collectSpecializedImplementors( TypeElement type, Set set, + List bindings ) + { + Set result = new HashSet(); + Set toProcess = new HashSet(); + toProcess.add(type); + while (toProcess.size() > 0) { + TypeElement element = toProcess.iterator().next(); + toProcess.remove(element); + Set implementors = doCollectSpecializedImplementors( + element,bindings); + if (implementors.size() == 0) { + continue; + } + result.addAll(implementors); + for (TypeElement impl : implementors) { + toProcess.add(impl); + } + } + for (TypeElement derivedElement : result) { + if (!hasSpecializes(derivedElement, getHelper())) { + continue; + } + handleSuper(type, derivedElement, bindings, set); + } + } + + private Set doCollectSpecializedImplementors( TypeElement type, + List bindings ) + { + Set result = new HashSet(); + ElementHandle handle = ElementHandle.create(type); + final Set> handles = getHelper() + .getClasspathInfo().getClassIndex().getElements( + handle, + EnumSet.of(SearchKind.IMPLEMENTORS), + EnumSet + .of(SearchScope.SOURCE, + SearchScope.DEPENDENCIES)); + if (handles == null) { + LOGGER.log(Level.WARNING, + "ClassIndex.getElements() was interrupted"); // NOI18N + return Collections.emptySet(); + } + for (ElementHandle elementHandle : handles) { + LOGGER.log(Level.FINE, "found derived element {0}", elementHandle + .getQualifiedName()); // NOI18N + TypeElement derivedElement = elementHandle.resolve(getHelper(). + getCompilationController()); + if (derivedElement == null) { + continue; + } + result.add(derivedElement); + } + return result; + } + + private boolean handleInterface( TypeElement element, TypeElement child, + Set collectedElements , Set bindingTypes ) + { + /* interfaces could not be injectables , but let's inspect them as possible + * injectables for notifying user about error if any. + */ + List interfaces = child.getInterfaces(); + for (TypeMirror typeMirror : interfaces) { + if ( getHelper().getCompilationController().getTypes().isSameType( + element.asType(), typeMirror) ) + { + return true; + } + if ( getHelper().getCompilationController().getTypes(). + isAssignable( typeMirror, element.asType())) + { + Element el = getHelper().getCompilationController(). + getTypes().asElement( typeMirror ); + if ( !( el instanceof TypeElement )){ + return false; + } + TypeElement interfaceElement = (TypeElement)el; + if ( bindingTypes.contains( interfaceElement) ){ + return true; + } + collectedElements.add( interfaceElement); + if ( !hasSpecializes( interfaceElement , getHelper() ) ){ + return false; + } + else { + return handleInterface(element, interfaceElement, + collectedElements, bindingTypes ); + } + } + } + + return false; + } + + private void handleSuper(TypeElement type ,TypeElement child, + List bindings, Set set) + { + if ( !getHelper().getCompilationController().getTypes().isAssignable( + child.asType(), type.asType())) + { + return; + } + List superclasses = getHelper().getSuperclasses( + child); + Set collectedSuper = new HashSet(); + collectedSuper.add( child ); + boolean specializes = true; + TypeElement previous = child; + for (TypeElement superElement : superclasses) { + if (superElement.equals(type) || set.contains( superElement)) { + break; + } + if ( getHelper().getCompilationController().getTypes(). + isAssignable( superElement.asType(), type.asType())) + { + previous = superElement; + } + else { + if ( !hasSpecializes(superElement, getHelper())) { + specializes = false; + break; + } + collectedSuper.add(superElement); + specializes = handleInterface(type, previous, collectedSuper, set ); + break; + } + } + if (specializes) { + for (TypeElement superElement : collectedSuper) { + if (!set.contains(superElement)) { + set.add(superElement); + bindings.add(new BindingQualifier(getHelper(), superElement, + getAnnotationName())); + } + } + } + } + + static interface AnnotationHandleStrategy { + void handleAnnotation( AnnotationMirror mirror , TypeElement annotation ); + } + + static interface SpecializeVisitor { + boolean visit( TypeElement superElement ); + boolean visit( ExecutableElement overridenElement ); + } + + private AnnotationModelHelper myHelper; + private String myAnnotationName; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/ArchiveTypeBindingTypeFilter.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/ArchiveTypeBindingTypeFilter.java new file mode 100644 index 000000000000..ff28496b3d7d --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/ArchiveTypeBindingTypeFilter.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.Iterator; +import java.util.Set; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; + +/** + * since cdi 1.1 behavior is based on archoe type, beans may not be discoverable + * + * @author sp153251 + */ +public class ArchiveTypeBindingTypeFilter extends Filter { + + static ArchiveTypeBindingTypeFilter get(Class clazz) { + assertElement(clazz); + // could be changed to cached ThreadLocal access + if (clazz.equals(Element.class) || clazz.equals(TypeElement.class)) { + return (ArchiveTypeBindingTypeFilter) new ArchiveTypeBindingTypeFilter<>(); + } + return null; + } + private WebBeansModelImplementation myImpl; + + void init(WebBeansModelImplementation impl) { + myImpl = impl; + } + + @Override + void filter(Set set) { + super.filter(set); + if (myImpl.getBeansModel() != null) { + switch (myImpl.getBeansModel().getBeanArchiveType()) { + case NONE: + set.clear(); + break; + case IMPLICIT: + CompilationController compInfo = myImpl.getModel().getCompilationController(); + for (Iterator iterator = set.iterator(); iterator + .hasNext();) { + Element element = iterator.next(); + //TODO: reqwrite with ScopeChecker, avoid duplicates + boolean isNormalScopeOrScopeOrSingleton = AnnotationUtil.getAnnotationMirror(element, compInfo, + AnnotationUtil.NORMAL_SCOPE_FQN, + AnnotationUtil.SCOPE_FQN, + AnnotationUtil.REQUEST_SCOPE_FQN, + AnnotationUtil.SESSION_SCOPE_FQN, + AnnotationUtil.APPLICATION_SCOPE_FQN, + AnnotationUtil.CONVERSATION_SCOPE_FQN, + AnnotationUtil.DEPENDENT_SCOPE_FQN, + AnnotationUtil.CDISINGLETON) != null; + if (isNormalScopeOrScopeOrSingleton) { + continue; + } + if (AnnotationUtil.isSessionBean(element, compInfo)) { + continue; + } + iterator.remove(); + } + } + } + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/AssignabilityChecker.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/AssignabilityChecker.java new file mode 100644 index 000000000000..164a763bd161 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/AssignabilityChecker.java @@ -0,0 +1,149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.List; + +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.ReferenceType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; +import javax.lang.model.util.Types; + + +/** + * @author ads + * + */ +class AssignabilityChecker extends DelegateAssignabilityChecker { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#handleBothTypeVars(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror, javax.lang.model.util.Types) + */ + @Override + protected boolean handleBothTypeVars( TypeMirror argType, + TypeMirror varTypeArg, Types types ) + { + /* + * Implementation of spec item : + * the required type parameter and the bean type parameter are + * both type variables and the upper bound of the required + * type parameter is assignable to the upper bound, if any, + * of the bean type parameter + */ + return super.handleBothTypeVars(varTypeArg, argType, types); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#handleTypeVar(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror, javax.lang.model.util.Types) + */ + @Override + protected boolean handleBeanTypeVar( TypeMirror argType, TypeMirror varTypeArg, + Types types ) + { + /* + * Implementation of spec item : the required type parameter is an + * actual type, the bean type parameter is a type variable and the + * actual type is assignable to the upper bound, if any, of the type + * variable + */ + + return super.handleRequiredTypeVar( varTypeArg , argType, types ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#handleWildCardTypeVar(javax.lang.model.type.TypeMirror, javax.lang.model.util.Types, javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror) + */ + @Override + protected boolean handleWildCardTypeVar( TypeMirror argType, Types types, + TypeMirror upperBound, TypeMirror lowerBound ) + { + /* + * Implementation of spec item : + * the required type parameter is a wildcard, + * the bean type parameter is a type variable and the upper bound of the type + * variable is assignable to or assignable from the upper bound, + * if any, of the wildcard and assignable from the lower + * bound, if any, of the wildcard + */ + TypeMirror typeUpper = ((TypeVariable) argType).getUpperBound(); + + if (typeUpper == null || typeUpper.getKind() == TypeKind.NULL) { + return upperBound == null || upperBound.getKind() == TypeKind.NULL; + } + + if (upperBound == null || upperBound.getKind() == TypeKind.NULL) { + if (lowerBound == null || lowerBound.getKind() == TypeKind.NULL) { + return true; + } + else { + return checkIsAssignable(types, lowerBound, typeUpper); + } + } + else { + if (lowerBound == null || lowerBound.getKind() == TypeKind.NULL) { + return checkIsAssignable(types, typeUpper, upperBound) + || checkIsAssignable(types, upperBound, typeUpper); + } + else { + if ((isAssignable(typeUpper, upperBound, types) || isAssignable( + upperBound, typeUpper, types)) + && isAssignable(lowerBound, typeUpper, types)) + { + return true; + } + else if (typeUpper instanceof ReferenceType + && lowerBound instanceof ReferenceType) + { + return (checkAssignability((ReferenceType) upperBound, + (ReferenceType) typeUpper) || checkAssignability( + (ReferenceType) typeUpper, + (ReferenceType) upperBound)) + && checkAssignability((ReferenceType) typeUpper, + (ReferenceType) lowerBound); + } + else { + return false; + } + } + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#handleBeanRawType(javax.lang.model.util.Types, java.util.List, javax.lang.model.element.TypeElement) + */ + @Override + protected boolean handleBeanRawType( Types types, + List varTypeArguments, + TypeElement objectElement ) + { + return false; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.DelegateAssignabilityChecker#handleRequiredRawType(javax.lang.model.util.Types, java.util.List, javax.lang.model.element.TypeElement) + */ + @Override + protected boolean handleRequiredRawType( Types types, + List typeArguments, TypeElement objectElement ) + { + return super.handleBeanRawType(types, typeArguments, objectElement); + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/BeansFilter.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/BeansFilter.java new file mode 100644 index 000000000000..354d24fcd451 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/BeansFilter.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.Iterator; +import java.util.Set; + +import javax.lang.model.element.TypeElement; + + +/** + * @author ads + * + */ +class BeansFilter extends Filter { + + static BeansFilter get() { + return new BeansFilter(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.Filter#filter(java.util.Set) + */ + @Override + void filter( Set set ) { + super.filter(set); + for (Iterator iterator = set.iterator(); iterator + .hasNext();) + { + TypeElement element = iterator.next(); + String name = element.getQualifiedName().toString(); + if (name.startsWith("java.") ||name.startsWith("jakarta.")) { // NOI18N + iterator.remove(); + } + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/BeansModelImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/BeansModelImpl.java new file mode 100644 index 000000000000..bbb848689317 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/BeansModelImpl.java @@ -0,0 +1,504 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.logging.Logger; + +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.project.Project; +import org.netbeans.modules.jakarta.web.beans.CdiUtil; +import org.netbeans.modules.jakarta.web.beans.api.model.BeanArchiveType; +import org.netbeans.modules.jakarta.web.beans.api.model.BeansModel; +import org.netbeans.modules.jakarta.web.beans.api.model.ModelUnit; +import org.netbeans.modules.jakarta.web.beans.xml.Alternatives; +import org.netbeans.modules.jakarta.web.beans.xml.BeanClass; +import org.netbeans.modules.jakarta.web.beans.xml.BeanClassContainer; +import org.netbeans.modules.jakarta.web.beans.xml.Beans; +import org.netbeans.modules.jakarta.web.beans.xml.BeansAttributes; +import org.netbeans.modules.jakarta.web.beans.xml.Decorators; +import org.netbeans.modules.jakarta.web.beans.xml.Interceptors; +import org.netbeans.modules.jakarta.web.beans.xml.Stereotype; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansModelFactory; +import org.netbeans.modules.xml.retriever.catalog.Utilities; +import org.netbeans.modules.xml.xam.ModelSource; +import org.netbeans.modules.xml.xam.locator.CatalogModelException; +import org.openide.filesystems.FileAttributeEvent; +import org.openide.filesystems.FileChangeListener; +import org.openide.filesystems.FileEvent; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileRenameEvent; +import org.openide.filesystems.FileUtil; + + +/** + * @author ads + * + */ +public class BeansModelImpl implements BeansModel { + + private static final String META_INF = "META-INF"; //NOI18N + + private static final String BEANS_XML ="beans.xml"; //NOI18N + + private static final String WEB_INF = "WEB-INF"; //NOI18N + + private BeanArchiveType beanArchType = null; + + private Boolean isCdi11OrLater = null; + + public BeansModelImpl( ModelUnit unit ){ + myUnit = unit; + myLock = new Object(); + registerChangeListeners(); + initModels(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.BeansModel#getAlternativeClasses() + */ + public Set getAlternativeClasses() { + Set result = new HashSet(); + for( WebBeansModel model : getModels() ){ + Beans beans = model.getBeans(); + if ( beans == null ){ + // it could happen if model is not well formed xml ( or f.e. empty XML file ) + continue; + } + List alternatives = beans.getChildren(Alternatives.class); + for (Alternatives alternative : alternatives) { + List children = alternative.getChildren(BeanClass.class); + for (BeanClass beanClass : children) { + result.add( beanClass.getBeanClass()); + } + } + } + return result; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.BeansModel#getAlternativeStereotypes() + */ + public Set getAlternativeStereotypes() { + Set result = new HashSet(); + for( WebBeansModel model : getModels() ){ + Beans beans = model.getBeans(); + if ( beans == null ){ + // it could happen if model is not well formed xml ( or f.e. empty XML file ) + continue; + } + List alternatives = beans.getChildren(Alternatives.class); + for (Alternatives alternative : alternatives) { + List children = alternative.getChildren(Stereotype.class); + for (Stereotype stereotype : children) { + result.add( stereotype.getStereotype()); + } + } + } + return result; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.BeansModel#getDecoratorClasses() + */ + public LinkedHashSet getDecoratorClasses() { + return getBeanClasses( Decorators.class ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.BeansModel#getIntercetorClasses() + */ + public LinkedHashSet getInterceptorClasses() { + return getBeanClasses( Interceptors.class ); + } + + public LinkedHashSet getBeanClasses( Class clazz) { + LinkedHashSet result = new LinkedHashSet(); + for (WebBeansModel model : getModels()) { + Beans beans = model.getBeans(); + if ( beans == null ){ + // it could happen if model is not well formed xml ( or f.e. empty XML file ) + continue; + } + List children = beans.getChildren(clazz); + for (BeanClassContainer container : children) { + List beansClasses = container.getBeansClasses(); + for (BeanClass beanClass : beansClasses) { + result.add( beanClass.getBeanClass()); + } + } + } + return result; + } + + @Override + public BeanArchiveType getBeanArchiveType() { + if(beanArchType == null) { + Project project = getUnit().getProject(); + if(project != null) { + // + CdiUtil lookup = project.getLookup().lookup( CdiUtil.class ); + // + if( lookup == null ) { + if (!CdiUtil.isCdiEnabled(project)) { + // no CDI + beanArchType = BeanArchiveType.NONE; + } else if (!CdiUtil.isCdi11OrLater(project)) { + // CDI 1.0 behaves like explicit bean archive + beanArchType = BeanArchiveType.EXPLICIT; + } else { + beanArchType = getBeansArchiveType(); + } + } else { + if (!lookup.isCdiEnabled()) { + // no CDI + beanArchType = BeanArchiveType.NONE; + } else if (!lookup.isCdi11OrLater()) { + // CDI 1.0 behaves like explicit bean archive + beanArchType = BeanArchiveType.EXPLICIT; + } else { + beanArchType = getBeansArchiveType(); + } + } + } else { + //there is no perfect solution. may happens in tests and may be in stand alone file opening, default as in cdi1.0 + beanArchType = BeanArchiveType.EXPLICIT; + } + } + return beanArchType; + } + + @Override + public boolean isCdi11OrLater() { + if (isCdi11OrLater == null) { + Project project = getUnit().getProject(); + if (project != null) { + CdiUtil lookup = project.getLookup().lookup(CdiUtil.class); + if (lookup == null) { + isCdi11OrLater = CdiUtil.isCdiEnabled(project) && CdiUtil.isCdi11OrLater(project); + } else { + isCdi11OrLater = lookup.isCdiEnabled() && lookup.isCdi11OrLater(); + } + } else { + // there is no perfect solution. may happens in tests and may be in stand alone file opening, default as in cdi1.0 + isCdi11OrLater = false; + } + } + return isCdi11OrLater; + } + + private void registerChangeListeners() { + + ClassPath compile = getUnit().getCompilePath(); + compile.addPropertyChangeListener(new PropertyChangeListener() { + + public void propertyChange( PropertyChangeEvent arg0 ) { + /* + * Synchronization is needed only at initModels() call. + */ + synchronized (myLock) { + if ( myModels == null ){ + return; + } + FileObject[] roots = getUnit().getCompilePath() + .getRoots(); + Set rootsSet = new HashSet(Arrays + .asList(roots)); + Set oldRoots = new HashSet( + myCompileRootToModel.keySet()); + Set intersection = new HashSet( + rootsSet); + intersection.retainAll(oldRoots); + oldRoots.removeAll(rootsSet); + for (FileObject fileObject : oldRoots) { + List remove = myCompileRootToModel. + remove(fileObject); + myModels.removeAll(remove); + } + rootsSet.removeAll(intersection); + for (FileObject fileObject : rootsSet) { + addCompileModels( fileObject , myModels); + } + } + } + }); + + myListener = new FileChangeListener(){ + + public void fileAttributeChanged( FileAttributeEvent arg0 ) { + } + + public void fileChanged( FileEvent event ) { + //TODO, drop beanArchType here? if it's beans.xml + if ( !checkBeansFile(event.getFile())){//heavy operation? + return; + } + beanArchType = null; + } + + public void fileDataCreated( FileEvent event ) { + FileObject file = event.getFile(); + if ( !checkBeansFile(file)){ + return; + } + ModelSource source= getModelSource(file, true ); + beanArchType = null; + if ( source!= null ){ + WebBeansModel model = WebBeansModelFactory.getInstance(). + getModel( source ); + synchronized( myLock ){ + if ( myModels == null ){ + return; + } + myModels.add( model ); + } + } + } + + public void fileDeleted( FileEvent event ) { + FileObject file = event.getFile(); + if ( !wasBeansFile(file)){ + return; + } + WebBeansModel model = null; + beanArchType = null; + synchronized (myLock) { + if ( myModels == null){ + return; + } + for (WebBeansModel mod : myModels) { + FileObject fileObject = mod.getModelSource() + .getLookup().lookup(FileObject.class); + if (fileObject.equals(event.getFile())) { + model = mod; + break; + } + } + if (model != null) { + myModels.remove(model); + } + + } + } + + public void fileFolderCreated( FileEvent arg0 ) { + } + + public void fileRenamed( FileRenameEvent arg0 ) { + } + + private boolean checkBeansFile( FileObject fileObject ){ + if ( fileObject == null){ + return false; + } + FileObject[] roots = getUnit().getSourcePath().getRoots(); + for (FileObject root : roots) { + FileObject meta = root.getFileObject(META_INF); + if ( meta != null && fileObject.equals( meta.getFileObject(BEANS_XML) )){ + return true; + } + FileObject webInf = root.getFileObject( WEB_INF ); + if ( webInf!=null && fileObject.equals( webInf.getFileObject(BEANS_XML))){ + return true; + } + } + return false; + } + + private boolean wasBeansFile( FileObject fileObject ){ + if ( fileObject == null){ + return false; + } + String name = fileObject.getNameExt(); + if ( name.equals( BEANS_XML )) + { + FileObject parent = fileObject.getParent(); + if ( !parent.getName().equals( META_INF ) && + !parent.getName().equals( WEB_INF )) + { + return false; + } + for ( FileObject root : getUnit().getSourcePath().getRoots()){ + if ( parent.equals(root.getFileObject(META_INF)) + ||parent.equals(root.getFileObject(WEB_INF))) + { + return true; + } + } + } + return false; + } + }; + + FileUtil.addFileChangeListener( myListener ); + } + + private void initModels() { + /* + * synchronization is needed only at time of "initModels" work. + * It prevent simultaneous work initModels and registered listeners . + * All subsequent access to myModels could be done without synchronization + * because of chosen class for myModels ( it is CopyOnWrite ). + */ + synchronized ( myLock ) { + List list = new LinkedList(); + FileObject[] roots = getUnit().getSourcePath().getRoots(); + for (FileObject fileObject : roots) { + addModels(fileObject,list); + } + FileObject[] compileRoots = getUnit().getCompilePath().getRoots(); + for (FileObject root : compileRoots) { + addCompileModels( root ,list); + } + myModels = new CopyOnWriteArrayList( list ); + } + } + + private void addCompileModels( FileObject root , List list ) { + FileObject beans = getBeansFile(root); + if (beans != null){ + addCompileModel(beans, root, list); + } + } + + /** + * is based on cdi 1.1, do not use for 1.0 + * @return + */ + private synchronized BeanArchiveType getBeansArchiveType() { + for (FileObject fileObject : getUnit().getSourcePath().getRoots()) { + FileObject beans = getBeansFile(fileObject); + if (beans != null) { + beanArchiveType = detectArchiveType(beans); + return beanArchiveType; + } + } + for (FileObject fileObject : getUnit().getCompilePath().getRoots()) { + FileObject beans = getBeansFile(fileObject); + if (beans != null) { + beanArchiveType = detectArchiveType(beans); + return beanArchiveType; + } + } + beanArchiveType = BeanArchiveType.IMPLICIT;//no beans.xmk is found, in 1.1 it means implicit/annotated + return beanArchiveType; + } + + private BeanArchiveType detectArchiveType(FileObject beans) { + WebBeansModel model = WebBeansModelFactory.getInstance().getModel(getModelSource(beans, true)); + if (model == null || model.getRootComponent()==null) { + return BeanArchiveType.IMPLICIT; + } + + String attribute = model.getRootComponent().getAttribute(BeansAttributes.BEAN_DISCOVERY_MODE); + if(attribute == null) { + attribute = "all";//NOI18N, got this for cdi 1.0, but there should be a better place for check, CdiUtil.isCdi11OrLater isn't good for ee7 server wih 1.0 beans.xml + } + switch(attribute) { + case "none": //NOI18N + return BeanArchiveType.NONE; + case "all": //NOI18N + return BeanArchiveType.EXPLICIT; + case "annotated": //NOI18N + default: + return BeanArchiveType.IMPLICIT; + } + } + + private FileObject getBeansFile(FileObject root) { + FileObject beans = null; + FileObject meta = root.getFileObject(META_INF); + if(meta != null) beans = meta.getFileObject(BEANS_XML); + if (beans != null) { + return beans; + } + FileObject web = root.getFileObject(WEB_INF); + return web != null ? web.getFileObject(BEANS_XML) : null; + } + + void addCompileModel(FileObject fileObject, FileObject compileRoot, + List modelList ) + { + WebBeansModel model = WebBeansModelFactory.getInstance().getModel( + getModelSource(fileObject, false)); + if ( model != null ){ + modelList.add( model ); + List list = myCompileRootToModel.get(compileRoot ); + if ( list == null ){ + list = new ArrayList<>(2); + myCompileRootToModel.put( compileRoot , list ); + } + list.add( model ); + } + } + + private void addModels( FileObject root , List list ) { + FileObject beans = getBeansFile(root); + if (beans != null){ + addModel(beans, list ); + } + } + + void addModel( FileObject beans , List list ) { + WebBeansModel model = WebBeansModelFactory.getInstance().getModel( + getModelSource(beans, true)); + if ( model != null ){ + list.add( model ); + } + } + + private ModelSource getModelSource( FileObject fileObject , + boolean isEditable ) + { + try { + return Utilities.createModelSource( fileObject,isEditable); + } catch (CatalogModelException ex) { + Logger.getLogger("global").log(java.util.logging.Level.SEVERE, + ex.getMessage(), ex); // NOI18N + } + return null; + } + + private List getModels(){ + return myModels; + } + + private ModelUnit getUnit(){ + return myUnit; + } + + private ModelUnit myUnit; + private Object myLock; + private List myModels; + private Map> myCompileRootToModel = new HashMap<>(); + private FileChangeListener myListener; + private BeanArchiveType beanArchiveType; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/BindingQualifier.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/BindingQualifier.java new file mode 100644 index 000000000000..6190ce6308da --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/BindingQualifier.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.List; +import java.util.Map; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.PersistentObject; + + +/** + * @author ads + * + */ +class BindingQualifier extends PersistentObject { + + BindingQualifier( AnnotationModelHelper helper, TypeElement typeElement, + String annotation ) + { + super(helper, typeElement); + myAnnotation = annotation; + refresh( typeElement); + } + + String getAnnotationName(){ + return myAnnotation; + } + + boolean refresh( TypeElement type ) { + List allAnnotationMirrors = + getHelper().getCompilationController().getElements(). + getAllAnnotationMirrors(type); + Map annotationsByType = + getHelper().getAnnotationsByType( allAnnotationMirrors ); + if ( annotationsByType.get( getAnnotationName()) != null ){ + return true; + } + return AnnotationObjectProvider.checkSuper(type, getAnnotationName(), + getHelper())!= null; + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals( Object obj ) { + if ( obj instanceof BindingQualifier ){ + return ((BindingQualifier)obj).getTypeElement().equals( getTypeElement()); + } + else { + return false; + } + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return getTypeElement().hashCode(); + } + + private String myAnnotation; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/Bundle.properties b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/Bundle.properties new file mode 100644 index 000000000000..99cbf71d8158 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/Bundle.properties @@ -0,0 +1,45 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +ERR_MultipleDisposes=Method {0} has several parameters with @Disposes annotation +ERR_MultipleObserves=Method {0} has several parameters with @Observes annotation +ERR_DisposesHasObserves=Method {0} is declared as disposer but also has \ +parameter annotated @Observes +ERR_DisposesHasInjectOrProduces=Method {0} is declared as disposer but also has \ +{1} annotation +ERR_ObserverHasInjectOrProduces=Method {0} is declared as observer but also has \ +{1} annotation + + +# Result errors +ERR_ProducerInjectPoint=Element {0} has @Producer annotation and cannot be \ +an injection point. +ERR_NoInjectPoint=Element {0} does not have @Inject annotation and cannot be \ +an injection point. +ERR_BadParent=Expected type definition as enclosing element for {0}. But found {1} element. + +ERR_UnresolvedAmbiguousDependency=Unresolved ambiguous dependency found as \ +result of typesafe resolution +ERR_NoFound=Unsatisfied dependency\: no bean matches the injection point +ERR_AlternativesOnly=Only turned off eligible for injection alternatives are found +ERR_NoEnabledBeans=No enabled eligible for injection beans are found +ERR_DefaultScopeCollision=Element does not explicitly declare scope but its \ +stereotypes has different stereotypes that declare different default scopes: {0} and {1}. +ERR_InitializedInjectionPoint=Injection point should not be initialized explicitly. +ERR_StaticInjectionPoint=Injection point should not be static. +ERR_FinalInjectionPoint=Injection point should not be final. +ERR_InjectPointTypeVar=Injection point should not be a type variable. +ERR_SeveralScopes=Element may specify at most one scope type annotation. diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/Checker.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/Checker.java new file mode 100644 index 000000000000..eeec3a41ce04 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/Checker.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + + +/** + * @author ads + * + */ +interface Checker { + + boolean check(); +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/DecoratorInterceptorLogic.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/DecoratorInterceptorLogic.java new file mode 100644 index 000000000000..27732d195859 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/DecoratorInterceptorLogic.java @@ -0,0 +1,410 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationHelper; +import org.netbeans.modules.jakarta.web.beans.impl.model.results.InterceptorsResultImpl; +import org.netbeans.modules.jakarta.web.beans.impl.model.results.ResultImpl; + + +/** + * @author ads + * + */ +abstract class DecoratorInterceptorLogic extends EventInjectionPointLogic { + + DecoratorInterceptorLogic( WebBeansModelImplementation model ) { + super(model); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider#getDecorators(javax.lang.model.element.TypeElement) + */ + @Override + public Collection getDecorators( TypeElement element ) { + Collection decorators = getModel(). + getDecoratorsManager().getObjects(); + + Collection result = new ArrayList( decorators.size()); + for (DecoratorObject decoratorObject : decorators) { + TypeElement decorator = decoratorObject.getTypeElement(); + if ( isDecoratorFor( decorator , element )){ + result.add( decorator ); + } + } + return result; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider#getInterceptorBindings(javax.lang.model.element.Element) + */ + @Override + public Collection getInterceptorBindings( Element element ){ + final InterceptorBindingChecker interceptorChecker = new InterceptorBindingChecker( + getModel().getHelper() ); + final StereotypeChecker stereotypeChecker = new StereotypeChecker( + getModel().getHelper().getHelper()); + TransitiveAnnotationHandler handler = new IntereptorBindingHandler( + interceptorChecker, stereotypeChecker); + Set result = new HashSet(); + transitiveVisitAnnotatedElements(element, result, + getModel().getHelper().getHelper(), handler); + + if ( element.getKind() == ElementKind.METHOD ){ + TypeElement enclosedClass = getCompilationController(). + getElementUtilities().enclosingTypeElement(element); + Collection classBindings = getInterceptorBindings( + enclosedClass ); + result.addAll( classBindings ); + } + return result; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider#getInterceptors(javax.lang.model.element.Element) + */ + @Override + public InterceptorsResultImpl getInterceptors( Element element ) { + Collection interceptors = getModel(). + getInterceptorsManager().getObjects(); + Set result = new HashSet(); + + Collection elementBindings = getInterceptorBindings(element); + Set elementBindingsFqns = getAnnotationFqns(elementBindings); + + for (InterceptorObject interceptor : interceptors) { + TypeElement typeElement = interceptor.getTypeElement(); + if ( hasInterceptorBindings( typeElement , elementBindingsFqns )){ + result.add(typeElement); + } + } + filterBindingsByMembers(elementBindings, result, TypeElement.class); + return getInterceptorsResult( element , result ); + } + + private InterceptorsResultImpl getInterceptorsResult( Element element, + Set interceptors ) + { + LinkedHashSet interceptorClasses = getModel().getBeansModel(). + getInterceptorClasses(); + List enabledInterceptors = new ArrayList( + interceptors.size()); + for (String fqn : interceptorClasses) { + TypeElement interceptor = getCompilationController().getElements(). + getTypeElement(fqn); + if ( interceptors.contains( interceptor )){ + enabledInterceptors.add( interceptor ); + } + } + interceptors.removeAll( enabledInterceptors ); + InterceptorsResultImpl result = new InterceptorsResultImpl( element , + enabledInterceptors , interceptors , getModel().getHelper() ); + return result; + } + + static void transitiveVisitAnnotatedElements( Element element, + Set result,AnnotationHelper helper, + TransitiveAnnotationHandler handler ) + { + List annotationMirrors = helper + .getCompilationInfo().getElements().getAllAnnotationMirrors(element); + for (AnnotationMirror annotationMirror : annotationMirrors) { + if (result.contains(annotationMirror)) { + continue; + } + Element annotationElement = annotationMirror.getAnnotationType().asElement(); + if ( !( annotationElement instanceof TypeElement )){ + continue; + } + boolean isTargetAnnotation = handler.isTargetAnotation( + (TypeElement)annotationElement); + if ( isTargetAnnotation ){ + result.add(annotationMirror); + } + if (handler.proceed(element, (TypeElement)annotationElement, + isTargetAnnotation)) + { + transitiveVisitAnnotatedElements((TypeElement)annotationElement, + result,helper, handler ); + } + } + } + + private boolean hasInterceptorBindings( TypeElement typeElement, + Set elementBindings) + { + Collection requiredBindings = getInterceptorBindings( typeElement ); + Set requiredInterceptorFqns = getAnnotationFqns( requiredBindings ); + + // element should contain all interceptor binding declared for Interceptor + return elementBindings.containsAll(requiredInterceptorFqns) ; + } + + private boolean isDecoratorFor( TypeElement decorator, TypeElement element ) { + /* + * Tripple is used to get delegate Element and its TypeMirror. + * If @Delegate injection point should be declared in each Decorator + * explicitly then TypeMirror could be gotten as ".asType()" from + * element and tripple is not needed. + * It is unclear from the spec about inheritance delegate injection point + * ( plain injection point is inherited ). So it is possble when + * injection point is defined in the superclass and child inherit + * this injection point without overloading it. + * In the latter case injection point should be considered from + * the child point of view. TipeMirror access in this case is not + * so simple for delegate method parameter. + */ + Triple data = + getDelegateInjectionPoint(decorator); + if ( data == null ){ + return false; + } + VariableElement delegate = data.getFirst(); + TypeMirror delegateType = data.getSecond(); + Set set = new HashSet(); + set.add( element ); + /* + * Check assignability of delegate injection point and decorated type + */ + filterBindingsByType(delegate, delegateType, set); + if ( set.isEmpty() ){ + return false; + } + /* + * Now delegate type is matched to the decorated type and one need + * to check just matching delegate qualifiers + */ + return checkQualifiers(element, delegate, delegateType, set); + } + + private Triple getDelegateInjectionPoint( + TypeElement decorator ) + { + List allMembers = getCompilationController().getElements(). + getAllMembers( decorator ); + List fields = ElementFilter.fieldsIn(allMembers); + for (VariableElement field : fields) { + if ( AnnotationObjectProvider.hasAnnotation(field, + DELEGATE_ANNOTATION, getModel().getHelper() ) && + AnnotationObjectProvider.hasAnnotation(field, + INJECT_ANNOTATION, getModel().getHelper() )) + { + TypeMirror delegateType = getCompilationController().getTypes(). + asMemberOf((DeclaredType)decorator.asType(), field); + return new Triple(field, + delegateType, null); + } + } + + Triple result; + List methods = ElementFilter.methodsIn(allMembers); + List ctors = ElementFilter.constructorsIn(allMembers); + Set allMethods = new LinkedHashSet(); + allMethods.addAll( ctors ); + allMethods.addAll( methods ); + for (ExecutableElement method : allMethods) { + if ( !AnnotationObjectProvider.hasAnnotation(method, INJECT_ANNOTATION, + getModel().getHelper())){ + continue; + } + result = getDelegate(method, decorator); + if ( result != null ){ + return result; + } + } + + return null; + } + + private Triple getDelegate( + ExecutableElement method, TypeElement decorator ) + { + List parameters = method.getParameters(); + int index =0; + VariableElement delegate = null; + for (VariableElement variableElement : parameters) { + if ( AnnotationObjectProvider.hasAnnotation(variableElement, + DELEGATE_ANNOTATION, getModel().getHelper())) + { + delegate = variableElement; + break; + } + index ++; + } + if ( delegate == null ){ + return null; + } + ExecutableType methodType = (ExecutableType)getCompilationController(). + getTypes().asMemberOf((DeclaredType)decorator.asType(), method ); + List parameterTypes = methodType.getParameterTypes(); + TypeMirror typeMirror = parameterTypes.get(index); + return new Triple(delegate, typeMirror, null); + } + + private boolean checkQualifiers( TypeElement element, VariableElement delegate, + TypeMirror delegateType, Set set ) + { + List quilifierAnnotations = new LinkedList(); + boolean anyQualifier = false; + try { + anyQualifier = hasAnyQualifier(delegate, false, false, quilifierAnnotations); + } + catch(InjectionPointDefinitionError e ){ + return false; + } + + boolean defaultQualifier = !anyQualifier && quilifierAnnotations.size() == 0; + boolean newQualifier = false; + + if ( quilifierAnnotations.size() == 1 ){ + newQualifier = getModel().getHelper().hasAnnotation(quilifierAnnotations, + NEW_QUALIFIER_ANNOTATION); + defaultQualifier = getModel().getHelper().hasAnnotation(quilifierAnnotations, + DEFAULT_QUALIFIER_ANNOTATION); + + } + else if ( quilifierAnnotations.size() == 0 && anyQualifier) { + // Just @Any case + return true; + } + if ( defaultQualifier ) { + // @Default qualifier + if ( hasImplicitDefaultQualifier(element)){ + return true; + } + else { + List qualifiers = getQualifiers(element, true); + return getModel().getHelper().hasAnnotation(qualifiers, + DEFAULT_QUALIFIER_ANNOTATION); + } + } + else if (newQualifier){ + ResultImpl lookupResult = handleNewQualifier(delegate, delegateType, + quilifierAnnotations); + Set typeElements = lookupResult.getTypeElements(); + return typeElements.contains( element ); + } + + if ( !checkQualifiers(element, quilifierAnnotations) ){ + return false; + } + + filterBindingsByMembers(quilifierAnnotations, set, TypeElement.class ); + return !set.isEmpty(); + } + + private boolean checkQualifiers( TypeElement element, + List quilifierAnnotations ) + { + Set requiredAnnotationFqns = getAnnotationFqns(quilifierAnnotations); + + List elementAnnotations = + getQualifiers(element, true); + Set elementAnnotationFqns = getAnnotationFqns(elementAnnotations); + + if ( requiredAnnotationFqns.contains(DEFAULT_QUALIFIER_ANNOTATION) && + !elementAnnotationFqns.contains(DEFAULT_QUALIFIER_ANNOTATION) && + !hasImplicitDefaultQualifier(element)) + { + return false; + } + requiredAnnotationFqns.remove(DEFAULT_QUALIFIER_ANNOTATION); + return elementAnnotationFqns.containsAll(requiredAnnotationFqns); + } + + private static final class IntereptorBindingHandler implements + TransitiveAnnotationHandler + { + + private IntereptorBindingHandler( + InterceptorBindingChecker interceptorChecker, + StereotypeChecker stereotypeChecker ) + { + this.interceptorChecker = interceptorChecker; + this.stereotypeChecker = stereotypeChecker; + } + + @Override + public boolean proceed( Element annotatedElement, + TypeElement element , boolean isTargetAnnotation) + { + /* + * proceed until annotation is either interceptor binding or stereotype + */ + if ( isTargetAnnotation ){ + return true; + } + + stereotypeChecker.init(element); + boolean isStereotype = stereotypeChecker.check(); + stereotypeChecker.clean(); + + if ( isStereotype && + annotatedElement.getKind() == ElementKind.ANNOTATION_TYPE ) + { + /* + * only stereotypes are transitive : interceptor binding + * annotated by stereotype doesn't have interceptor bindings + * of stereotype + */ + stereotypeChecker.init((TypeElement)annotatedElement); + isStereotype = stereotypeChecker.check(); + stereotypeChecker.clean(); + } + return isStereotype; + } + + @Override + public boolean isTargetAnotation( TypeElement element ) { + interceptorChecker.init(element); + boolean isInterceptor = interceptorChecker.check(); + interceptorChecker.clean(); + return isInterceptor; + } + + private final InterceptorBindingChecker interceptorChecker; + private final StereotypeChecker stereotypeChecker; + } + + interface TransitiveAnnotationHandler { + boolean proceed(Element annotatedElement, TypeElement element, + boolean isTargerAnnotation ); + boolean isTargetAnotation(TypeElement element ); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/DecoratorObject.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/DecoratorObject.java new file mode 100644 index 000000000000..ab11eb6fe678 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/DecoratorObject.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.List; +import java.util.Map; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.PersistentObject; +import org.netbeans.modules.jakarta.web.beans.impl.model.AbstractObjectProvider.Refreshable; + + +/** + * @author ads + * + */ +class DecoratorObject extends PersistentObject implements Refreshable { + + DecoratorObject( AnnotationModelHelper helper, + TypeElement typeElement ) + { + super(helper, typeElement); + boolean valid = refresh(typeElement); + assert valid; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractObjectProvider.Refreshable#refresh(javax.lang.model.element.TypeElement) + */ + @Override + public boolean refresh( TypeElement type ) { + List allAnnotationMirrors = + getHelper().getCompilationController().getElements(). + getAllAnnotationMirrors(type); + Map annotationsByType = + getHelper().getAnnotationsByType( allAnnotationMirrors ); + return annotationsByType.get( EnableBeansFilter.DECORATOR) != null ; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/DecoratorObjectProvider.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/DecoratorObjectProvider.java new file mode 100644 index 000000000000..8bbba9b7edd8 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/DecoratorObjectProvider.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; + + +/** + * @author ads + * + */ +class DecoratorObjectProvider extends AbstractObjectProvider { + + DecoratorObjectProvider( AnnotationModelHelper helper ) { + super( EnableBeansFilter.DECORATOR, helper); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractObjectProvider#createTypeElement(javax.lang.model.element.TypeElement) + */ + @Override + protected DecoratorObject createTypeElement( TypeElement element ) { + return new DecoratorObject( getHelper() , element ); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/DefaultBindingTypeFilter.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/DefaultBindingTypeFilter.java new file mode 100644 index 000000000000..665d21ca1f6b --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/DefaultBindingTypeFilter.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; + +/** + * @author ads + */ +class DefaultBindingTypeFilter extends Filter { + + static DefaultBindingTypeFilter get( Class clazz ) + { + assertElement(clazz); + // could be changed to cached ThreadLocal access + if (clazz.equals(Element.class)) { + return (DefaultBindingTypeFilter) new DefaultBindingTypeFilter(); + } + else if (clazz.equals(TypeElement.class)) { + return (DefaultBindingTypeFilter) new DefaultBindingTypeFilter(); + } + return null; + } + + void init( WebBeansModelImplementation impl ) { + myImpl = impl; + } + + /* + * (non-Javadoc) + * @see + * org.netbeans.modules.jakarta.web.beans.impl.model.Filter#filter(java.util.Set) + */ + @Override + void filter( Set set ) { + super.filter(set); + for (Iterator iterator = set.iterator(); iterator + .hasNext();) + { + Element element = iterator.next(); + List allAnnotationMirrors = getImplementation() + .getHelper().getCompilationController().getElements() + .getAllAnnotationMirrors(element); + Set qualifierNames = new HashSet(); + for (AnnotationMirror annotationMirror : allAnnotationMirrors) { + DeclaredType annotationType = annotationMirror + .getAnnotationType(); + TypeElement annotationElement = (TypeElement) annotationType + .asElement(); + if ( annotationElement == null ){ + continue; + } + String annotationName = annotationElement.getQualifiedName() + .toString(); + if ( WebBeansModelProviderImpl.ANY_QUALIFIER_ANNOTATION.equals( + annotationName) || + WebBeansModelProviderImpl.NAMED_QUALIFIER_ANNOTATION.equals( + annotationName)) + { + continue; + } + if (isQualifier(annotationElement)) { + qualifierNames.add(annotationName); + } + } + if ( qualifierNames.contains( + WebBeansModelProviderImpl.DEFAULT_QUALIFIER_ANNOTATION)) + { + continue; + } + if ( (element instanceof TypeElement) && ( + AnnotationObjectProvider.checkSuper((TypeElement)element, + WebBeansModelProviderImpl.DEFAULT_QUALIFIER_ANNOTATION, + getImplementation().getHelper())!=null )) + { + continue; + } + else if ( element instanceof ExecutableElement ){ + Element specialized = + MemberCheckerFilter.getSpecialized( (ExecutableElement)element, + getImplementation(), + WebBeansModelProviderImpl.DEFAULT_QUALIFIER_ANNOTATION); + if ( specialized!= null){ + continue; + } + } + if (qualifierNames.size() != 0) { + iterator.remove(); + } + } + } + + private boolean isQualifier( TypeElement annotationElement ) { + return AnnotationObjectProvider.isQualifier(annotationElement, + getImplementation().getHelper(), false ); + } + + private WebBeansModelImplementation getImplementation() { + return myImpl; + } + + private WebBeansModelImplementation myImpl; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/DelegateAssignabilityChecker.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/DelegateAssignabilityChecker.java new file mode 100644 index 000000000000..34eb3bcf7575 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/DelegateAssignabilityChecker.java @@ -0,0 +1,262 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.Collection; +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ReferenceType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; +import javax.lang.model.util.Types; + + +/** + * @author ads + * + */ +class DelegateAssignabilityChecker extends AbstractAssignabilityChecker { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#hasBeanType(javax.lang.model.element.Element, javax.lang.model.type.ReferenceType) + */ + @Override + protected boolean hasBeanType( Element element, ReferenceType variableType) { + Types types = getImplementation().getHelper(). + getCompilationController().getTypes(); + Collection restrictedTypes = RestrictedTypedFilter. + getRestrictedTypes( element, getImplementation()); + // return false if restricted types don't contain injection point type + if ( restrictedTypes != null ) { + boolean hasBeanType = false; + for( TypeMirror restrictedType : restrictedTypes ){ + if ( types.isSameType( types.erasure( restrictedType ) , + types.erasure(variableType))) + { + hasBeanType = true; + break; + } + } + if ( !hasBeanType ){ + return false; + } + } + return true; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#checkAssignability(javax.lang.model.type.ReferenceType, javax.lang.model.type.ReferenceType) + */ + @Override + public boolean checkAssignability( ReferenceType variableType , + ReferenceType refType ) + { + if ( refType instanceof DeclaredType ){ + return checkAssignability(variableType, refType, + ((DeclaredType)refType).asElement()); + } + else { + return super.checkAssignability(variableType, refType); + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#handleBothTypeVars(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror, javax.lang.model.util.Types) + */ + @Override + protected boolean handleBothTypeVars( TypeMirror argType, + TypeMirror varTypeArg, Types types ) + { + /* + * Implementation of spec item : + * the delegate type parameter and the bean type parameter are both + * type variables and the upper bound of the bean type + * parameter is assignable to the upper bound, + * if any, of the delegate type parameter + */ + TypeMirror upper = ((TypeVariable)argType).getUpperBound(); + TypeMirror upperVar = ((TypeVariable)varTypeArg).getUpperBound(); + + if ( upperVar == null || upperVar.getKind() == TypeKind.NULL ){ + return true; + } + if ( upper == null || upper.getKind() == TypeKind.NULL ){ + return false; + } + + return checkIsAssignable(types, upper, upperVar); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#handleTypeVar(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror, javax.lang.model.util.Types) + */ + @Override + protected boolean handleBeanTypeVar( TypeMirror argType, TypeMirror varTypeArg, + Types types ) + { + return false; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#handleWildCardTypeVar(javax.lang.model.type.TypeMirror, javax.lang.model.util.Types, javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror) + */ + @Override + protected boolean handleWildCardTypeVar( TypeMirror argType, Types types, + TypeMirror upperBound, TypeMirror lowerBound ) + { + /* + * Implementation of spec item : + * the delegate type parameter is a wildcard, the bean + * type parameter is a type variable and the upper bound of the type + * variable is assignable to the upper bound, + * if any, of the wildcard and assignable from the lower bound, + * if any, of the wildcard + */ + TypeMirror typeUpper = ((TypeVariable) argType).getUpperBound(); + + if (typeUpper == null || typeUpper.getKind() == TypeKind.NULL) { + return upperBound == null || upperBound.getKind() == TypeKind.NULL; + } + + if (upperBound == null || upperBound.getKind() == TypeKind.NULL) { + if (lowerBound == null || lowerBound.getKind() == TypeKind.NULL) { + return true; + } + else { + return checkIsAssignable(types, lowerBound, typeUpper); + } + } + else { + if (lowerBound == null || lowerBound.getKind() == TypeKind.NULL) { + return checkIsAssignable(types, typeUpper, upperBound); + } + else{ + return checkIsAssignable(types, typeUpper, upperBound) + && checkIsAssignable(types, lowerBound, typeUpper); + } + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#isAssignable(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror, javax.lang.model.util.Types) + */ + @Override + protected boolean isAssignable( TypeMirror from, TypeMirror to, Types types ) + { + if ( !super.isAssignable(from, to, types) ){ + return false; + } + else { + Element fromElement = types.asElement(from); + Collection restrictedTypes = RestrictedTypedFilter + .getRestrictedTypes(fromElement, + getImplementation()); + if (restrictedTypes == null) { + return getImplementation().getHelper() + .getCompilationController().getTypes() + .isAssignable(from, to); + } + for ( TypeMirror restrictedType : restrictedTypes ){ + if ( types.isSameType( types.erasure(restrictedType), + types.erasure( to ))) + { + return true; + } + } + return false; + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#handleBeanRawType(javax.lang.model.util.Types, java.util.List, javax.lang.model.element.TypeElement) + */ + @Override + protected boolean handleBeanRawType( Types types, + List typeArguments, TypeElement objectElement ) + { + // bean type is a raw. + for (TypeMirror typeParam : typeArguments) { + /* + * From the spec: + * A raw bean type is considered assignable to a parameterized + * delegate type if the raw types are identical and all type parameters + * of the delegate type are either unbounded type variables or java.lang.Object. + */ + if (typeParam.getKind() == TypeKind.DECLARED) { + if (!((TypeElement)((DeclaredType) typeParam).asElement()). + getQualifiedName().contentEquals(Object.class.getCanonicalName())) + { + return false; + } + } + else if ( typeParam.getKind() == TypeKind.TYPEVAR){ + TypeMirror lowerBound = ((TypeVariable)typeParam).getLowerBound(); + if ( lowerBound != null && lowerBound.getKind() != TypeKind.NULL ){ + return false; + } + TypeMirror upperBound = ((TypeVariable)typeParam).getUpperBound(); + if ( upperBound != null && upperBound.getKind() != TypeKind.NULL + && objectElement!= null ) + { + return types.isSameType(upperBound, objectElement.asType()); + } + } + else { + return false; + } + } + return true; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#handleRequiredRawType(javax.lang.model.util.Types, java.util.List, javax.lang.model.element.TypeElement) + */ + @Override + protected boolean handleRequiredRawType( Types types, + List varTypeArguments, + TypeElement objectElement ) + { + return false; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#handleRequiredTypeVar(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror, javax.lang.model.util.Types) + */ + @Override + protected boolean handleRequiredTypeVar( TypeMirror argType, + TypeMirror varTypeArg, Types types ) + { + /* + * Implementation of spec item : the delegate type parameter is a + * type variable, the bean type parameter is an actual type, and the + * actual type is assignable to the upper bound, if any, of the type variable + */ + + TypeMirror upper = ((TypeVariable)varTypeArg).getUpperBound(); + if ( upper == null || upper.getKind()== TypeKind.NULL ){ + return true; + } + return checkIsAssignable(types, argType, upper); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/EnableBeansFilter.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/EnableBeansFilter.java new file mode 100644 index 000000000000..73f7a679b093 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/EnableBeansFilter.java @@ -0,0 +1,597 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; +import javax.lang.model.type.WildcardType; +import javax.lang.model.util.ElementFilter; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.api.model.BeansModel; +import org.netbeans.modules.jakarta.web.beans.api.model.CdiException; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.impl.model.results.ErrorImpl; +import org.netbeans.modules.jakarta.web.beans.impl.model.results.InjectableResultImpl; +import org.netbeans.modules.jakarta.web.beans.impl.model.results.InjectablesResultImpl; +import org.netbeans.modules.jakarta.web.beans.impl.model.results.ResolutionErrorImpl; +import org.netbeans.modules.jakarta.web.beans.impl.model.results.ResultImpl; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +class EnableBeansFilter { + + static final String DECORATOR = "jakarta.decorator.Decorator"; // NOI18N + + static final String EXTENSION = "jakarta.enterprise.inject.spi.Extension";// NOI18N + + static String SCOPE = "jakarta.inject.Scope"; // NOI18N + + private final HashSet predefinedBeans; + { + predefinedBeans = new HashSet<>(); + predefinedBeans.add(EventInjectionPointLogic.EVENT_INTERFACE); + predefinedBeans.add("jakarta.servlet.http.HttpServletRequest");//NOI18N + predefinedBeans.add("jakarta.servlet.http.HttpSession");//NOI18N + predefinedBeans.add("jakarta.servlet.ServletContext");//NOI18N + predefinedBeans.add("jakarta.jms.JMSContext");//NOI18N + predefinedBeans.add(AnnotationUtil.INJECTION_POINT);//NOI18N + predefinedBeans.add("jakarta.enterprise.inject.spi.BeanManager");//NOI18N + predefinedBeans.add("jakarta.transaction.UserTransaction");//NOI18N + predefinedBeans.add("java.security.Principal");//NOI18N + predefinedBeans.add("jakarta.validation.ValidatorFactory");//NOI18N + predefinedBeans.add("jakarta.faces.application.Application");//NOI18N + predefinedBeans.add("jakarta.faces.annotation.ApplicationMap");//NOI18N + predefinedBeans.add("jakarta.faces.annotation.FlowMap");//NOI18N + predefinedBeans.add("jakarta.faces.annotation.HeaderMap");//NOI18N + predefinedBeans.add("jakarta.faces.annotation.HeaderValuesMap");//NOI18N + predefinedBeans.add("jakarta.faces.annotation.InitParameterMap");//NOI18N + predefinedBeans.add("jakarta.faces.annotation.ManagedProperty");//NOI18N + predefinedBeans.add("jakarta.faces.annotation.RequestCookieMap");//NOI18N + predefinedBeans.add("jakarta.faces.annotation.RequestMap");//NOI18N + predefinedBeans.add("jakarta.faces.annotation.RequestParameterMap");//NOI18N + predefinedBeans.add("jakarta.faces.annotation.RequestParameterValuesMap");//NOI18N + predefinedBeans.add("jakarta.faces.annotation.SessionMap");//NOI18N + predefinedBeans.add("jakarta.faces.annotation.ViewMap");//NOI18N + predefinedBeans.add("jakarta.faces.context.ExternalContext");//NOI18N + predefinedBeans.add("jakarta.faces.context.FacesContext");//NOI18N + }; + + private final HashMap predefinedBeanAnnotationPairs; + { + predefinedBeanAnnotationPairs = new HashMap<>(); + predefinedBeanAnnotationPairs.put("jakarta.faces.flow.builder.FlowBuilder","jakarta.faces.flow.builder.FlowBuilderParameter");//NOI18N + }; + + EnableBeansFilter(ResultImpl result, WebBeansModelImplementation model , + boolean programmatic ) + { + myResult = result; + myHelper = model.getHelper(); + myBeansModel = model.getBeansModel(); + myModel = model; + isProgrammatic = programmatic; + } + + DependencyInjectionResult filter(AtomicBoolean cancel){ + myAlternatives = new HashSet(); + myEnabledAlternatives = new HashSet(); + + PackagingFilter filter = new PackagingFilter(getWebBeansModel()); + Set typeElements = getResult().getTypeElements(); + + TypeElement firstElement = typeElements.size()>0 ? typeElements.iterator().next() : null; + + // remove elements defined in compile class path which doesn't have beans.xml + filter.filter( typeElements, cancel ); + for (TypeElement typeElement : typeElements) { + if ( getResult().isAlternative(typeElement)){ + myAlternatives.add( typeElement ); + addEnabledAlternative( typeElement , typeElement); + } + } + // remove elements defined in compile class path which doesn't have beans.xml + Set productions = packagedFilterProductions ( ); + + for (Element element : productions) { + TypeElement enclosingTypeElement = myHelper.getCompilationController(). + getElementUtilities().enclosingTypeElement(element); + if ( getResult().isAlternative(element)){ + myAlternatives.add( element ); + addEnabledAlternative( enclosingTypeElement , element ); + } + } + + Set enabledTypeElements = new HashSet( typeElements ); + Set enabledProductions = new HashSet( productions ); + myAlternatives.removeAll(myEnabledAlternatives); + // now myAlternative contains only disabled alternatives. + enabledProductions.removeAll( myAlternatives ); + enabledTypeElements.removeAll( myAlternatives ); + + int typesSize = enabledTypeElements.size(); + int productionsSize = enabledProductions.size(); + + // filter enabled/disabled beans + Set enabledTypes = findEnabledTypes( enabledTypeElements ); + findEnabledProductions( enabledProductions); + int commonSize = enabledTypes.size() + enabledProductions.size(); + if ( commonSize == 1 ){ + Element injectable = enabledTypes.size() ==0 ? + enabledProductions.iterator().next(): + enabledTypes.iterator().next(); + enabledTypes.addAll( enabledProductions); + return new InjectableResultImpl( getResult(), injectable, enabledTypes ); + } + if ( commonSize ==0 ){ + //no implementation on classpath/sources or it's fileterd by common logic(for usual beans) + //first check if we have a class in white list (i.e. must be implemented in ee7 environment) + String nm = myResult.getVariableType().toString(); + if(nm.startsWith("jakarta.") || nm.startsWith("java.")) {//NOI18N + InjectableResultImpl res = handleEESpecificImplementations(getResult(), firstElement, enabledTypes); + if(res != null) { + return res; + } + } + // + if ( typeElements.size() == 0 && productions.size() == 0 ){ + return new ErrorImpl(getResult().getVariable(), + getResult().getVariableType(), NbBundle.getMessage( + EnableBeansFilter.class, "ERR_NoFound")); // NOI18N + } + if ( typesSize==0 && productionsSize == 0 ) + { + /* no elements was eliminated after check for "enabling" + * ( by the spec ). So they are all alternatives that + * was not turned on in beans.xml. + */ + return new ResolutionErrorImpl(getResult(), NbBundle.getMessage( + EnableBeansFilter.class, "ERR_AlternativesOnly")); // NOI18N + } + return new ResolutionErrorImpl( getResult(), NbBundle.getMessage( + EnableBeansFilter.class, "ERR_NoEnabledBeans")); // NOI18N + } + Set allElements = new HashSet( enabledTypes ); + allElements.addAll( enabledProductions ); + allElements.retainAll( myEnabledAlternatives ); + boolean hasSingleAlternative = allElements.size() == 1; + if ( hasSingleAlternative ){ + /* + * Spec : When an ambiguous dependency exists, the container attempts + * to resolve the ambiguity: + * - If any matching beans are alternatives, the container + * eliminates all matching beans that are not alternatives. + * If there is exactly one bean remaining, the container will select + * this bean, and the ambiguous dependency is called resolvable. + */ + enabledTypes.addAll( enabledProductions); + return new InjectableResultImpl( getResult(), + allElements.iterator().next(), enabledTypes ); + } + + enabledTypes.addAll( enabledProductions); + if ( isProgrammatic ){ + return new InjectablesResultImpl(getResult() , enabledTypes ); + } + else { + String message = NbBundle.getMessage(EnableBeansFilter.class, + "ERR_UnresolvedAmbiguousDependency"); // NOI81N + return new ResolutionErrorImpl(getResult(), message, enabledTypes); + } + } + + /* + * This method should filter production elements which are defined + * in the classes inside compile class path without beans.xml. + * But NB doesn't perform indexing and search for fields and methods + * inside compile class path at all so there will be no production + * elements inside compile class path. + * So I commented out this block of logic to avoid wasting time . + */ + private Set packagedFilterProductions() { + return getResult().getProductions(); + /*Map> productions = + getResult().getAllProductions(); + List filtered = new ArrayList( productions.size()); + for (Entry> entry : productions.entrySet()) { + Element element = entry.getKey(); + List list = entry.getValue(); + int size = list.size(); + PackagingFilter filter = new PackagingFilter(myModel); + filter.filterTypes( list ); + if ( list.size() == 0 ){ + filtered.add( element ); + } + } + for( Element element : filtered ){ + productions.remove( element ); + } + return productions.keySet();*/ + } + + private void findEnabledProductions(Set productions ) + { + /* + * This is partial implementation of the spec : + * A bean is said to be enabled if: + * - it is not a producer method or field of a disabled bean + * Full check for enabled/disabled bean is very complicated. + * Here is check only for enabled alternatives if any. + */ + for (Iterator iterator = productions.iterator(); + iterator.hasNext(); ) + { + Element element = iterator.next(); + TypeElement enclosingTypeElement = getHelper(). + getCompilationController().getElementUtilities(). + enclosingTypeElement(element); + if ( getResult().isAlternative(enclosingTypeElement)){ + String name = enclosingTypeElement.getQualifiedName().toString(); + if ( getResult().hasAlternative(enclosingTypeElement) ){ + if ( !getModel().getAlternativeClasses().contains( name ) ){ + iterator.remove(); + } + } + if ( !alternativeStereotypesEnabled(enclosingTypeElement) ){ + iterator.remove(); + } + } + } + } + + private Set findEnabledTypes(Set elements) { + LinkedList types = new LinkedList( elements ); + Set result = new HashSet( elements ); + while( types.size() != 0 ) { + TypeElement typeElement = (TypeElement)types.remove(); + if ( !checkClass( typeElement )){ + result.remove( typeElement ); + continue; + } + checkProxyability( typeElement , types, result ); + checkSpecializes(typeElement, types, result , elements ); + } + return result; + } + + private boolean checkClass( TypeElement element ){ + if ( element.getKind() != ElementKind.CLASS ){ + return false; + } + Set modifiers = element.getModifiers(); + + Element enclosing = element.getEnclosingElement(); + if ( !( enclosing instanceof PackageElement) ){ + /* + * If class is inner class then it should be static. + */ + if ( !modifiers.contains( Modifier.STATIC ) ){ + return false; + } + } + Elements elements = getHelper().getCompilationController().getElements(); + Types types = getHelper().getCompilationController().getTypes(); + + List allAnnotations = elements. + getAllAnnotationMirrors(element); + + if ( modifiers.contains( Modifier.ABSTRACT ) && + !getHelper().hasAnnotation(allAnnotations, DECORATOR ) ) + { + /* + * If class is abstract it should be Decorator. + */ + return false; + } + TypeElement extensionElement = elements.getTypeElement( EXTENSION ); + if ( extensionElement!= null ){ + TypeMirror extensionType = extensionElement.asType(); + /* + * Class doesn't implement Extension + */ + if ( types.isAssignable( element.asType(), extensionType )){ + return false; + } + } + /* + * There should be either no parameters CTOR or CTOR is annotated with @Inject + */ + List constructors = ElementFilter.constructorsIn( + element.getEnclosedElements()); + boolean foundCtor = constructors.size() ==0; + for (ExecutableElement ctor : constructors) { + if ( ctor.getParameters().size() == 0 ){ + foundCtor = true; + break; + } + if ( getHelper().hasAnnotation(allAnnotations, + FieldInjectionPointLogic.INJECT_ANNOTATION)) + { + foundCtor = true; + break; + } + } + return foundCtor; + } + + private void checkProxyability( TypeElement typeElement, + LinkedList types , Set elements) + { + try { + String scope = ParameterInjectionPointLogic.getScope(typeElement, + getWebBeansModel().getHelper()); + Elements elementsUtil = getHelper().getCompilationController(). + getElements(); + TypeElement scopeElement = elementsUtil.getTypeElement(scope); + /* + * Client proxies are never required for a bean whose + * scope is a pseudo-scope such as @Dependent. + */ + if ( scopeElement == null || + getHelper().hasAnnotation( elementsUtil.getAllAnnotationMirrors( + scopeElement), SCOPE) ) + { + return; + } + } + catch (CdiException e) { + types.remove( typeElement ); + elements.remove( typeElement); + return; + } + /* + * Certain legal bean types cannot be proxied by the container: + * - classes which don't have a non-private constructor with no parameters, + * - classes which are declared final or have final methods, + * - primitive types, + * - and array types. + */ + if ( hasModifier(typeElement, Modifier.FINAL)){ + types.remove(typeElement); + elements.remove( typeElement ); + return; + } + checkFinalMethods(typeElement, types, elements); + + List constructors = ElementFilter.constructorsIn( + typeElement.getEnclosedElements()) ; + boolean appropriateCtor = false; + for (ExecutableElement constructor : constructors) { + if ( hasModifier(constructor, Modifier.PRIVATE)){ + continue; + } + if ( constructor.getParameters().size() == 0 ){ + appropriateCtor = true; + break; + } + } + + if ( !appropriateCtor){ + types.remove(typeElement); + elements.remove( typeElement ); + } + } + + private void checkFinalMethods( TypeElement typeElement, + LinkedList types, Set elements ) + { + TypeMirror variableType = getResult().getVariableType(); + DeclaredType beanType = getDeclaredType( variableType ); + if ( beanType == null ){ + return; + } + Element beanElement = beanType.asElement(); + if ( !( beanElement instanceof TypeElement )){ + return; + } + List methods = ElementFilter.methodsIn( + getHelper().getCompilationController().getElements().getAllMembers( + (TypeElement)beanElement)) ; + TypeElement objectElement = getHelper().getCompilationController(). + getElements().getTypeElement(Object.class.getCanonicalName()); + for (ExecutableElement executableElement : methods) { + // Skip Object methods , Fix for BZ#201825 - suspicious messages for @Injection + if ( executableElement.getEnclosingElement().equals( objectElement ) ){ + continue; + } + if ( hasModifier(executableElement, Modifier.FINAL)){ + types.remove(typeElement); + elements.remove( typeElement ); + return; + } + Element overloaded = getHelper().getCompilationController(). + getElementUtilities().getImplementationOf(executableElement, + typeElement); + if ( overloaded == null ){ + continue; + } + if ( hasModifier(overloaded, Modifier.FINAL)){ + types.remove(typeElement); + elements.remove( typeElement ); + return; + } + } + } + + private DeclaredType getDeclaredType( TypeMirror type ){ + if ( type instanceof DeclaredType && type.getKind()!= TypeKind.ERROR){ + return (DeclaredType)type; + } + if ( type instanceof TypeVariable ){ + TypeMirror upperBound = ((TypeVariable)type).getUpperBound(); + return getDeclaredType( upperBound ); + } + else if ( type instanceof WildcardType ){ + TypeMirror extendsBound = ((WildcardType)type).getExtendsBound(); + return getDeclaredType( extendsBound ); + } + return null; + } + + private boolean hasModifier ( Element element , Modifier mod){ + Set modifiers = element.getModifiers(); + for (Modifier modifier : modifiers) { + if (modifier == mod) { + return true; + } + } + return false; + } + + private void checkSpecializes( TypeElement typeElement, + LinkedList beans, Set resultElementSet, + Set originalElements) + { + TypeElement current = typeElement; + while( current != null ){ + TypeMirror superClass = current.getSuperclass(); + if (!(superClass instanceof DeclaredType)) { + break; + } + if (!AnnotationObjectProvider.hasSpecializes(current, getHelper())) { + break; + } + TypeElement superElement = (TypeElement) ((DeclaredType) superClass) + .asElement(); + if (originalElements.contains(superElement)) { + resultElementSet.remove(superElement); + } + beans.remove( superElement ); + if ( !getResult().getTypeElements().contains( superElement)){ + break; + } + current = superElement; + } + } + + private void addEnabledAlternative( TypeElement typeElement , Element element) { + String name = typeElement.getQualifiedName().toString(); + if ( getResult().hasAlternative(element) ){ + if ( !getModel().getAlternativeClasses().contains( name ) ){ + return; + } + /* + * I have commented the code below but I'm not sure is it + * correct. Specification doesn't mention the case + * when @Alternative annotation presents along with + * alternative Stereotypes. + * + * if ( getModel().getAlternativeClasses().contains( name ) ){ + * myEnabledAlternatives.add( element ); + return; + } + */ + } + if ( alternativeStereotypesEnabled(element)){ + myEnabledAlternatives.add( element ); + } + } + + private boolean alternativeStereotypesEnabled( Element element ){ + List stereotypes = getResult().getStereotypes(element); + for (AnnotationMirror annotationMirror : stereotypes) { + DeclaredType annotationType = annotationMirror.getAnnotationType(); + TypeElement annotationTypeElement = (TypeElement)annotationType.asElement(); + if ( getResult().isAlternative(annotationTypeElement) ){ + if ( getResult().hasAlternative(annotationTypeElement) ){ + String name = annotationTypeElement.getQualifiedName().toString(); + if ( !getModel().getAlternativeStereotypes().contains(name) ){ + return false; + } + } + else if ( !alternativeStereotypesEnabled(annotationTypeElement) ){ + return false; + } + } + } + return true; + } + + private ResultImpl getResult(){ + return myResult; + } + + private BeansModel getModel(){ + return myBeansModel; + } + + private AnnotationModelHelper getHelper(){ + return myHelper; + } + + private WebBeansModelImplementation getWebBeansModel(){ + return myModel; + } + + private Set myAlternatives; + private Set myEnabledAlternatives; + private ResultImpl myResult; + private final AnnotationModelHelper myHelper; + private final BeansModel myBeansModel; + private WebBeansModelImplementation myModel; + private boolean isProgrammatic; + + + + private InjectableResultImpl handleEESpecificImplementations(ResultImpl result, TypeElement firstElement, Set enabledTypes) { + if(result.getVariable() != null) { + String nm = result.getVariable().asType().toString(); + int c = nm.indexOf('<'); + if(c>0) { + nm = nm.substring(0,c); + } + if(predefinedBeans.contains(nm)) { + return new InjectableResultImpl( getResult(), firstElement, enabledTypes ); + } + String ann = predefinedBeanAnnotationPairs.get(nm); + if(ann != null) {//NOI18N + for(AnnotationMirror am:result.getVariable().getAnnotationMirrors()) { + if(ann.equals(am.getAnnotationType().toString())) {//NOI18N + return new InjectableResultImpl( getResult(), firstElement, enabledTypes ); + } + } + } + } + return null; + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/EventAssignabilityChecker.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/EventAssignabilityChecker.java new file mode 100644 index 000000000000..414cd2ce7ab2 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/EventAssignabilityChecker.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.ReferenceType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; +import javax.lang.model.util.Types; + + +/** + * @author ads + * + */ +public class EventAssignabilityChecker extends AbstractAssignabilityChecker { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#checkParameter(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror) + */ + @Override + protected boolean checkParameter( TypeMirror argType, TypeMirror varTypeArg ) + { + if ( varTypeArg.getKind()== TypeKind.TYPEVAR ){ + Types types = getImplementation().getHelper().getCompilationController(). + getTypes(); + TypeMirror upperBound = ((TypeVariable)varTypeArg).getUpperBound(); + if ( upperBound == null || upperBound.getKind() == TypeKind.NULL ){ + return true; + } + else { + return checkIsAssignable(types, argType, upperBound); + } + } + return super.checkParameter(argType, varTypeArg); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#hasBeanType(javax.lang.model.element.Element, javax.lang.model.type.ReferenceType) + */ + @Override + protected boolean hasBeanType( Element element , ReferenceType variableType) { + // Event assignability has no additional requirements + return true; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#handleRawType(javax.lang.model.util.Types, java.util.List, javax.lang.model.element.TypeElement) + */ + @Override + protected boolean handleRequiredRawType( Types types, + List typeArguments, TypeElement objectElement ) + { + /* Variable type is a raw. + * From the spec for event type : A parameterized event type + * is considered assignable to a raw observed event type + * if the raw types are identical. + */ + return true; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#handleBeanRawType(javax.lang.model.util.Types, java.util.List, javax.lang.model.element.TypeElement) + */ + @Override + protected boolean handleBeanRawType( Types types, + List varTypeArguments, + TypeElement objectElement ) + { + return false; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#handleTypeVar(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror, javax.lang.model.util.Types) + */ + @Override + protected boolean handleBeanTypeVar( TypeMirror argType, TypeMirror varTypeArg, + Types types ) + { + return false; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#handleBothTypeVars(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror, javax.lang.model.util.Types) + */ + @Override + protected boolean handleBothTypeVars( TypeMirror argType, + TypeMirror varTypeArg, Types types ) + { + return false; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#handleWildCardTypeVar(javax.lang.model.type.TypeMirror, javax.lang.model.util.Types, javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror) + */ + @Override + protected boolean handleWildCardTypeVar( TypeMirror argType, Types types, + TypeMirror upperBound, TypeMirror lowerBound ) + { + return false; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#isAssignable(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror, javax.lang.model.util.Types) + */ + @Override + protected boolean isAssignable( TypeMirror from, TypeMirror to, Types types ) + { + if ( !super.isAssignable(from, to, types) ){ + return false; + } + else { + return getImplementation().getHelper().getCompilationController(). + getTypes().isAssignable(from, to); + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker#handleRequiredTypeVar(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror, javax.lang.model.util.Types) + */ + @Override + protected boolean handleRequiredTypeVar( TypeMirror argType, + TypeMirror varTypeArg, Types types ) + { + return false; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/EventInjectionPointLogic.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/EventInjectionPointLogic.java new file mode 100644 index 000000000000..86d5314f471c --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/EventInjectionPointLogic.java @@ -0,0 +1,514 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Name; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.ReferenceType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; + +import org.netbeans.api.java.source.ClassIndex.SearchKind; +import org.netbeans.api.java.source.ClassIndex.SearchScope; +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationHandler; +import org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker.AssignabilityType; + + +/** + * @author ads + * + */ +abstract class EventInjectionPointLogic extends ParameterInjectionPointLogic { + + public static final String EVENT_INTERFACE = + "jakarta.enterprise.event.Event"; // NOI18N + + + EventInjectionPointLogic(WebBeansModelImplementation model ) { + super( model ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider#getObservers(javax.lang.model.element.VariableElement, javax.lang.model.type.DeclaredType) + */ + @Override + public List getObservers( VariableElement element, + DeclaredType parentType) + { + DeclaredType parent = parentType; + try { + parent = getParent(element, parentType); + } + catch (DefinitionError e) { + return null; + } + + TypeMirror type = getParameterType(element, parent, EVENT_INTERFACE); + if ( type == null || type.getKind() == TypeKind.ERROR ){ + return Collections.emptyList(); + } + + List qualifierAnnotations = new LinkedList(); + try { + hasAnyQualifier(element, true, true ,qualifierAnnotations); + } + catch(InjectionPointDefinitionError e ){ + return null; + } + boolean hasAny = qualifierAnnotations.size()==0; + + final List methodObservesParameters = + findObservesParameters(); + + Map parameterTypesMap = + new HashMap(); + for (ObserverTriple triple : methodObservesParameters ) { + ExecutableElement method = triple.getFirst(); + VariableElement parameter = triple.getSecond(); + int index = triple.getThird(); + TypeElement typeElement = getCompilationController(). + getElementUtilities().enclosingTypeElement( method ); + TypeMirror typeMirror = typeElement.asType(); + if ( typeMirror instanceof DeclaredType ){ + ExecutableType methodType = (ExecutableType) + getCompilationController().getTypes().asMemberOf( + (DeclaredType)typeMirror, method ); + List parameterTypes = methodType.getParameterTypes(); + + TypeMirror parameterType = parameterTypes.get( index ); + parameterTypesMap.put(parameter, parameterType); + } + + } + if ( !hasAny ){ + Set elements = parameterTypesMap.keySet(); + filterByQualifiers( qualifierAnnotations , elements); + filterBindingsByMembers(qualifierAnnotations, elements, Element.class); + } + + List result = new ArrayList( + parameterTypesMap.size()); + filterParametersByType( parameterTypesMap , type ); + for( Element parameter : parameterTypesMap.keySet() ){ + Element method = parameter.getEnclosingElement(); + if ( method.getKind() == ElementKind.METHOD){ + result.add( (ExecutableElement)method); + } + } + return result; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider#getObserverParameter(javax.lang.model.element.ExecutableElement) + */ + @Override + public VariableElement getObserverParameter( ExecutableElement element ) + { + Triple result = + doGetObserverParameter(element); + if ( result == null ){ + return null; + } + else { + return result.getFirst(); + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider#getEventInjectionPoints(javax.lang.model.element.ExecutableElement, javax.lang.model.type.DeclaredType) + */ + @Override + public List getEventInjectionPoints( + ExecutableElement element, DeclaredType parentType ) + { + DeclaredType parent = parentType; + try { + parent = getParent(element, parentType); + } + catch (DefinitionError e) { + return null; + } + + TypeMirror type = getCompilationController().getTypes().asMemberOf(parent, + element ); + + Triple parameterInfo = + doGetObserverParameter(element); + VariableElement parameter = parameterInfo.getFirst(); + int index = parameterInfo.getSecond(); + + if ( parameter == null ){ + return Collections.emptyList(); + } + + List eventInjectionPoints = getEventInjectionPoints(); + + filterByQualifiers( eventInjectionPoints, parameter); + + List parameterTypes = ((ExecutableType)type).getParameterTypes(); + + TypeMirror parameterType = parameterTypes.get( index ); + + filterEventInjectionsByType( eventInjectionPoints, parameterType); + return eventInjectionPoints; + } + + private List getEventInjectionPoints( ) + { + final List eventInjection = new LinkedList(); + try { + getModel().getHelper().getAnnotationScanner().findAnnotations(INJECT_ANNOTATION, + EnumSet.of( ElementKind.FIELD), new AnnotationHandler() { + + @Override + public void handleAnnotation( TypeElement type, + Element element, AnnotationMirror annotation ) + { + Element typeElement = getCompilationController().getTypes(). + asElement( element.asType() ); + if ( typeElement instanceof TypeElement && + element instanceof VariableElement ) + { + Name name = ((TypeElement)typeElement).getQualifiedName(); + if ( EVENT_INTERFACE.contentEquals( name )){ + eventInjection.add( (VariableElement) element); + } + } + } + }); + } + catch (InterruptedException e) { + LOGGER.warning("Finding annotation @Inject was interrupted"); // NOI18N + } + return eventInjection; + } + + private void filterByQualifiers( List qualifierAnnotations, + Set elements ) + { + Set requiredQualifiers = getAnnotationFqns(qualifierAnnotations); + + for (Iterator iterator = elements.iterator(); iterator.hasNext(); ) { + Element element = iterator.next(); + List annotationMirrors = + getCompilationController().getElements().getAllAnnotationMirrors( element ); + Set availableAnnotations = getAnnotationFqns(annotationMirrors); + if ( !availableAnnotations.containsAll( requiredQualifiers )){ + iterator.remove(); + } + } + } + + private void filterByQualifiers(List injectionPoints, + VariableElement parameter ) + { + List annotationMirrors = getCompilationController(). + getElements().getAllAnnotationMirrors( parameter ); + Set parameterAnnotations = getAnnotationFqns(annotationMirrors); + for (Iterator iterator = injectionPoints.iterator(); + iterator.hasNext() ; ) + { + VariableElement eventInjection = iterator.next(); + List eventQualifiers = new LinkedList(); + try { + hasAnyQualifier(eventInjection, true, true, eventQualifiers); + } + catch (InjectionPointDefinitionError e) { + iterator.remove(); + continue; + } + boolean hasAny = eventQualifiers.size() == 0; + if ( hasAny ){ + continue; + } + Set requiredQualifiers = getAnnotationFqns( eventQualifiers ); + if ( !parameterAnnotations.containsAll( requiredQualifiers) ){ + iterator.remove(); + continue; + } + if ( !checkQualifierMembers( eventQualifiers , annotationMirrors)){ + iterator.remove(); + continue; + } + } + } + + private boolean checkQualifierMembers( + List eventQualifiers, + List observerAnnotations ) + { + for (AnnotationMirror annotation : eventQualifiers) { + Map + elementValues = annotation.getElementValues(); + Set qualifierMembers = MemberBindingFilter. + collectBindingMembers( annotation, getModel()); + if ( !checkMember( elementValues , qualifierMembers, + observerAnnotations )) + { + return false; + } + } + return true; + } + + private boolean checkMember( + Map memberValues, + Set qualifierMembers, + List observerAnnotations ) + { + for( Entry entry : + memberValues.entrySet()) + { + ExecutableElement execElement = entry.getKey(); + AnnotationValue value = entry.getValue(); + if ( qualifierMembers.contains( execElement )) { + Element annotationElement = execElement.getEnclosingElement(); + if ( !( annotationElement instanceof TypeElement ) ){ + return false; + } + String annotationName = ((TypeElement)annotationElement). + getQualifiedName().toString(); + AnnotationMirror annotationMirror = getModel().getHelper() + .getAnnotationsByType(observerAnnotations).get(annotationName); + if ( annotationMirror == null ){ + return false; + } + Map + elementValues = annotationMirror.getElementValues(); + AnnotationValue valueForType = elementValues.get(execElement); + if (!MemberCheckerFilter.equals(value, valueForType)) { + return false; + } + } + } + return true; + } + + private Triple doGetObserverParameter( + ExecutableElement element ) + { + List parameters = element.getParameters(); + int index = 0 ; + for (VariableElement parameter : parameters) { + List allAnnotationMirrors = + getCompilationController().getElements(). + getAllAnnotationMirrors( parameter ); + for (AnnotationMirror annotationMirror : allAnnotationMirrors) { + DeclaredType annotationType = annotationMirror.getAnnotationType(); + TypeElement annotation = (TypeElement)annotationType.asElement(); + if ( annotation == null ){ + continue; + } + if ( OBSERVES_ANNOTATION.contentEquals( annotation.getQualifiedName())){ + return new Triple(parameter, index, null); + } + } + index++; + } + return null; + } + + private void filterParametersByType( + Map parameterTypesMap, TypeMirror type ) + { + AbstractAssignabilityChecker checker = AbstractAssignabilityChecker.get( + AssignabilityType.EVENT); + for (Iterator> iterator = + parameterTypesMap.entrySet().iterator();iterator.hasNext() ; ) + { + Entry entry = iterator.next(); + TypeMirror typeMirror = entry.getValue(); + + boolean assignable = isAssignable(type, typeMirror, checker); + + if ( !assignable ){ + iterator.remove(); + } + } + } + + private void filterEventInjectionsByType( + List eventInjectionPoints, + TypeMirror parameterType) + { + AbstractAssignabilityChecker checker = AbstractAssignabilityChecker.get( + AssignabilityType.EVENT ); + for (Iterator iterator = + eventInjectionPoints.iterator();iterator.hasNext() ; ) + { + VariableElement injection = iterator.next(); + TypeMirror type = getParameterType(injection, null, EVENT_INTERFACE); + + boolean assignable = isAssignable(type, parameterType, + checker); + + if ( !assignable ){ + iterator.remove(); + } + } + } + + private boolean isAssignable( TypeMirror subject , TypeMirror toType , + AbstractAssignabilityChecker checker) + { + if ( subject == null ){ + return false; + } + boolean assignable = false; + + Element typeElement = getCompilationController().getTypes().asElement( toType ); + + boolean isGeneric = (typeElement instanceof TypeElement) && + ((TypeElement)typeElement).getTypeParameters().size() != 0; + + if ( !isGeneric && getCompilationController(). + getTypes().isAssignable( subject, toType)) + { + return true; + } + + if ( subject instanceof ReferenceType && + toType instanceof ReferenceType) + { + checker.init((ReferenceType)toType, (ReferenceType)subject, getModel()); + assignable = checker.check(); + } + return assignable; + } + + /* + * Unfortunately annotation scanner ( getHelper().getAnnotationScanner() ) + * cannot be used for finding annotated method parameters. It doesn't + * work for them. So this method performs find usages of @Observes annotation + * and chooses appropriate elements. + */ + private List findObservesParameters() + { + List result = new LinkedList(); + CompilationController compilationController = + getModel().getHelper().getCompilationController(); + TypeElement observesType = compilationController.getElements().getTypeElement( + OBSERVES_ANNOTATION); + if ( observesType == null ){ + return result; + } + ElementHandle observesHandle = ElementHandle.create(observesType); + final Set> elementHandles = compilationController. + getClasspathInfo().getClassIndex().getElements( + observesHandle, + EnumSet.of(SearchKind.TYPE_REFERENCES), + EnumSet.of(SearchScope.SOURCE, SearchScope.DEPENDENCIES)); + for (ElementHandle elementHandle : elementHandles) { + TypeElement resolvedType = elementHandle.resolve( compilationController); + + List enclosedElements = resolvedType. + getEnclosedElements(); + List methods = ElementFilter.methodsIn( + enclosedElements); + for (ExecutableElement method : methods) { + List parameters = method.getParameters(); + int index = 0; + for (VariableElement parameter : parameters) { + List annotationMirrors = + compilationController.getElements(). + getAllAnnotationMirrors( parameter); + if ( getModel().getHelper().hasAnnotation( annotationMirrors, + OBSERVES_ANNOTATION) ){ + result.add( new ObserverTriple( method, parameter, index) ); + } + index++; + } + } + } + return result; + } + + static Set getAnnotationFqns( Collection annotations ) + { + Set annotationFqns = new HashSet(); + for (AnnotationMirror annotationMirror : annotations) { + DeclaredType annotationType = annotationMirror.getAnnotationType(); + Element annotationElement = annotationType.asElement(); + TypeElement annotation = (TypeElement) annotationElement; + if ( annotation == null ){ + continue; + } + annotationFqns.add( annotation.getQualifiedName().toString()); + } + return annotationFqns; + } + + private class ObserverTriple extends Triple{ + + ObserverTriple( ExecutableElement method, VariableElement parameter, + Integer index ) + { + super( method , parameter , index ); + } + } + + static class Triple { + Triple( T t , R r , S s){ + myFirst = t; + mySecond = r; + myThird = s; + } + + T getFirst(){ + return myFirst; + } + + R getSecond(){ + return mySecond; + } + + S getThird(){ + return myThird; + } + + private T myFirst; + private R mySecond; + private S myThird; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/FieldInjectionPointLogic.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/FieldInjectionPointLogic.java new file mode 100644 index 000000000000..e0a8d4e2c56b --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/FieldInjectionPointLogic.java @@ -0,0 +1,872 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.api.java.source.ClassIndex.SearchKind; +import org.netbeans.api.java.source.ClassIndex.SearchScope; +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.ElementUtilities; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationHandler; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.PersistentObjectManager; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.parser.AnnotationParser; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.parser.ParseResult; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.impl.model.results.DefinitionErrorResult; +import org.netbeans.modules.jakarta.web.beans.impl.model.results.ResultImpl; +import org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider; +import org.openide.util.NbBundle; + +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.Tree; +import com.sun.source.tree.VariableTree; +import java.util.concurrent.atomic.AtomicBoolean; +import org.netbeans.api.java.source.ClassIndex; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.api.model.BeanArchiveType; + +/** + * @author ads + */ +abstract class FieldInjectionPointLogic { + + static final String PRODUCER_ANNOTATION = + "jakarta.enterprise.inject.Produces"; // NOI18N + + static final String ANY_QUALIFIER_ANNOTATION = + "jakarta.enterprise.inject.Any"; // NOI18N + + static final String DEFAULT_QUALIFIER_ANNOTATION = + "jakarta.enterprise.inject.Default"; // NOI18N + + static final String NEW_QUALIFIER_ANNOTATION = + "jakarta.enterprise.inject.New"; // NOI18N + + static final String NAMED_QUALIFIER_ANNOTATION = + "jakarta.inject.Named"; // NOI18N + + static final String INJECT_ANNOTATION = + "jakarta.inject.Inject"; // NOI18N + + static final String INSTANCE_INTERFACE = + "jakarta.enterprise.inject.Instance"; // NOI18N + + static final String TYPED_RESTRICTION = + "jakarta.enterprise.inject.Typed"; // NOI18N + + static final String DELEGATE_ANNOTATION = + "jakarta.decorator.Delegate"; // NOI18N + + static final Logger LOGGER = Logger.getLogger(WebBeansModelProvider.class + .getName()); + + + FieldInjectionPointLogic( WebBeansModelImplementation model) { + myModel = model; + } + + public abstract TypeMirror resolveType( String fqn ) ; + + protected WebBeansModelImplementation getModel(){ + return myModel; + } + + protected DependencyInjectionResult findVariableInjectable( VariableElement element, + DeclaredType parentType , ResultLookupStrategy strategy, AtomicBoolean cancel ) + { + DeclaredType parent = parentType; + try { + parent = getParent(element, parentType); + } + catch ( DefinitionError e ){ + TypeElement type = e.getElement(); + return new DefinitionErrorResult(element, parentType, + NbBundle.getMessage(WebBeansModelProviderImpl.class, + "ERR_BadParent", element.getSimpleName(), // NOI18N + type!= null? type.toString(): null)); + } + + if(cancel.get()) { + return null; + } + + TypeMirror elementType = strategy.getType(getModel(), parent , element ); + + if(elementType instanceof DeclaredType && AnnotationUtil.PROVIDER.equals(""+((DeclaredType)elementType).asElement())) { + List typeArguments = ((DeclaredType)elementType).getTypeArguments(); + if(typeArguments!=null && typeArguments.size()>0) { + //in case of Provider we need to inspects type argument instead of Provider type, see #245546 + elementType = typeArguments.get(0); + } + } + + DependencyInjectionResult result = doFindVariableInjectable(element, elementType, true, cancel); + return strategy.getResult( getModel() , result, cancel ); + } + + protected DeclaredType getParent( Element element , DeclaredType parentType) + throws DefinitionError + { + DeclaredType parent = parentType; + if ( parent == null ){ + TypeElement type = getModel().getHelper().getCompilationController(). + getElementUtilities().enclosingTypeElement(element); + + boolean isDeclaredType = ( type.asType() instanceof DeclaredType ); + if ( isDeclaredType ){ + parent = (DeclaredType)type.asType(); + } + else { + throw new DefinitionError( type ); + } + } + return parent; + } + + protected DependencyInjectionResult doFindVariableInjectable( VariableElement element, + TypeMirror elementType, boolean injectRequired, AtomicBoolean cancel) + { + List quilifierAnnotations = new LinkedList(); + boolean anyQualifier = false; + try { + anyQualifier = hasAnyQualifier(element,injectRequired, false, + quilifierAnnotations); + } + catch(InjectionPointDefinitionError e ){ + return new DefinitionErrorResult(element, elementType, e.getMessage()); + } + + /* + * Single @Default annotation means increasing types that + * is eligible for injection. Each bean without any qualifiers + * type has @Default qualifier by default. So it should + * be also considered as injectable. + */ + boolean defaultQualifier = !anyQualifier && quilifierAnnotations.size() == 0; + /* + * The @New target is + * @Target(value={FIELD,PARAMETER}) + * and injectable couldn't have any other qualifiers. + * So @New should be the only qualifier for injection point + * and it could be assigned by user to bean type. + */ + boolean newQualifier = false; + String annotationName = null; + Set types = new HashSet(); + if ( quilifierAnnotations.size() == 1 ){ + AnnotationMirror annotationMirror = quilifierAnnotations.get( 0 ); + DeclaredType type = annotationMirror.getAnnotationType(); + TypeElement annotationElement = (TypeElement)type.asElement(); + if ( annotationElement != null ){ + annotationName = annotationElement.getQualifiedName().toString(); + defaultQualifier = annotationElement.getQualifiedName().contentEquals( + DEFAULT_QUALIFIER_ANNOTATION); + newQualifier = annotationElement.getQualifiedName().contentEquals( + NEW_QUALIFIER_ANNOTATION ); + } + } + if ( (quilifierAnnotations.size() == 0 && anyQualifier) || + defaultQualifier ) + { + LOGGER.fine("Found built-in binding "+annotationName); // NOI18N + Set assignableTypes = cancel.get() ? new HashSet() : getAssignableTypes( element , + elementType, cancel ); + if ( defaultQualifier ){ + LOGGER.fine("@Default annotation requires test for implementors" + + " of varaible type"); // NOI18N + /* + * Filter all appropriate types for presence qualifier. + * It should be either absent at all or qualifiers + * should contain @Default. + */ + filterBindingsByDefault( assignableTypes ); + filterBindingByArchiveType( assignableTypes ); + } + types.addAll( assignableTypes ); + } + else if (newQualifier){ + return handleNewQualifier(element, elementType, quilifierAnnotations); + } + else { + /* + * This is list with types that have all required qualifiers. This + * list will be used for further typesafe resolution. + */ + Set typesWithQualifiers = getBindingTypes( + quilifierAnnotations); + + filterBindingsByMembers(quilifierAnnotations, typesWithQualifiers, + TypeElement.class ); + + /* + * Now typesWithQualifiers contains appropriate types + * which has required qualifier with required parameters ( if any ). + * Next step is filter types via typesafe resolution. + */ + filterBindingsByType( element , elementType, typesWithQualifiers ); + types.addAll( typesWithQualifiers ); + } + + /* + * This is list with production fields or methods ( they have @Produces annotation ) + * that have all required bindings. + * This list will be also used for further typesafe resolution. + */ + Set productionElements; + if ( (quilifierAnnotations.size() == 0 && anyQualifier) || + defaultQualifier ) + { + productionElements = getAllProductions( ); + if ( defaultQualifier ){ + filterDefaultProductions( productionElements ); + } + } + else { + productionElements = getProductions( quilifierAnnotations, cancel); + filterBindingsByMembers( quilifierAnnotations , productionElements , + Element.class ); + } + filterProductionByType( element, elementType, productionElements ); + + return createResult( element, elementType, types , productionElements ); + } + + protected boolean isQualifier( TypeElement element, + AnnotationModelHelper helper, boolean event ) + { + return AnnotationObjectProvider.isQualifier(element, helper, event); + } + + protected Set getChildSpecializes( Element productionElement, + WebBeansModelImplementation model, AtomicBoolean cancel ) + { + TypeElement typeElement = model.getHelper().getCompilationController() + .getElementUtilities().enclosingTypeElement(productionElement); + Set implementors = getImplementors(model, typeElement, cancel); + implementors.remove( productionElement.getEnclosingElement()); + Set specializeElements = new HashSet(); + specializeElements.add(productionElement); + for (TypeElement implementor : implementors) { + if(cancel.get()) { + break; + } + inspectHierarchy(productionElement, implementor, + specializeElements, model); + } + specializeElements.remove(productionElement); + return specializeElements; + } + + protected boolean hasAnyQualifier( VariableElement element,boolean injectRequired, + boolean eventQualifiers, List quilifierAnnotations ) + throws InjectionPointDefinitionError + { + List annotations = + getModel().getHelper().getCompilationController().getElements(). + getAllAnnotationMirrors(element); + boolean isProducer = false; + + /* Single @Any annotation means skip searching in qualifiers . + * One need to check any bean that has required type . + * @Any qualifier type along with other qualifiers + * equivalent to the same list of qualifiers without @Any. + */ + boolean anyQualifier = false; + + boolean hasInject = false; + + for (AnnotationMirror annotationMirror : annotations) { + DeclaredType type = annotationMirror.getAnnotationType(); + TypeElement annotationElement = (TypeElement)type.asElement(); + if ( annotationElement == null ){ + continue; + } + if ( ANY_QUALIFIER_ANNOTATION.equals( + annotationElement.getQualifiedName().toString())) + { + anyQualifier = true; + } + else if ( isQualifier( annotationElement , getModel().getHelper(), + eventQualifiers) ) + { + quilifierAnnotations.add( annotationMirror ); + } + if ( PRODUCER_ANNOTATION.contentEquals( + annotationElement.getQualifiedName())) + { + isProducer = true; + } + else if ( INJECT_ANNOTATION.contentEquals( + annotationElement.getQualifiedName())) + { + hasInject = true; + } + } + if ( isProducer ){ + throw new InjectionPointDefinitionError( + NbBundle.getMessage( WebBeansModelProviderImpl.class, + "ERR_ProducerInjectPoint" , // NOI18N + element.getSimpleName() )); + } + if ( element.asType().getKind() == TypeKind.TYPEVAR ){ + throw new InjectionPointDefinitionError( + NbBundle.getMessage( WebBeansModelProviderImpl.class, + "ERR_InjectPointTypeVar" , // NOI18N + element.getSimpleName() )); + } + if ( injectRequired ){ + checkInjectionPoint(element); + } + if ( injectRequired && !hasInject ){ + throw new InjectionPointDefinitionError( + NbBundle.getMessage( WebBeansModelProviderImpl.class, + "ERR_NoInjectPoint" , // NOI18N + element.getSimpleName() )); + } + return anyQualifier; + } + + private void checkInjectionPoint( VariableElement element ) + throws InjectionPointDefinitionError + { + CompilationController compilationController = getModel().getHelper(). + getCompilationController(); + Tree tree = compilationController.getTrees().getTree( element ); + if ( tree instanceof VariableTree ){ + VariableTree varTree = (VariableTree)tree; + ExpressionTree initializer = varTree.getInitializer(); + if ( initializer != null ){ + throw new InjectionPointDefinitionError(NbBundle.getMessage( + FieldInjectionPointLogic.class, + "ERR_InitializedInjectionPoint")); // NOI18N + } + } + Set modifiers = element.getModifiers(); + if ( modifiers.contains(Modifier.STATIC)){ + throw new InjectionPointDefinitionError(NbBundle.getMessage( + FieldInjectionPointLogic.class, + "ERR_StaticInjectionPoint")); // NOI18N + } + if ( modifiers.contains(Modifier.FINAL)){ + throw new InjectionPointDefinitionError(NbBundle.getMessage( + FieldInjectionPointLogic.class, + "ERR_FinalInjectionPoint")); // NOI18N + } + } + + protected void filterBindingsByMembers( + Collection bindingAnnotations, + Set elementsWithBindings, Class clazz) + { + MemberBindingFilter filter = MemberBindingFilter.get( clazz ); + filter.init( bindingAnnotations, getModel() ); + filter.filter( elementsWithBindings ); + } + + protected void filterBindingsByType( VariableElement element, + TypeMirror elementType,Set typesWithBindings) + { + TypeBindingFilter filter = TypeBindingFilter.get(); + filter.init( elementType, element, getModel() ); + filter.filter( typesWithBindings ); + } + + protected ResultImpl handleNewQualifier( VariableElement element, + TypeMirror elementType,List quilifierAnnotations) + { + AnnotationMirror annotationMirror = quilifierAnnotations.get( 0 ); + AnnotationParser parser = AnnotationParser.create( getModel().getHelper()); + parser.expectClass( "value", null); // NOI18N + ParseResult parseResult = parser.parse(annotationMirror); + String clazz = parseResult.get( "value" , String.class ); // NOI18N + + TypeMirror typeMirror; + if ( clazz == null ){ + typeMirror = elementType; + } + else { + typeMirror = resolveType( clazz ); + } + Element typeElement = null; + if ( typeMirror != null ) { + typeElement = getModel().getHelper().getCompilationController(). + getTypes().asElement(typeMirror); + } + if ( typeElement!= null ){ + /* + * No need to look at implementors . + * Because they have qualifier @New(X.class) where X their class. + * X is binding parameter which should equals to binding + * parameter of @New qualifier for injection point. This + * parameter is typeMirror class . So X should + * be ONLY typeMirror class which is typeElement. + * types.addAll(getImplementors(modelImpl, typeElement )); + */ + if( getModel().getHelper().getCompilationController().getTypes(). + isAssignable(typeMirror, elementType)) + { + return new ResultImpl(element, elementType , (TypeElement)typeElement , + getModel().getHelper()); + } + } + return new ResultImpl(element, elementType, getModel().getHelper()); + } + + static Set getImplementors( WebBeansModelImplementation modelImpl, + Element typeElement, AtomicBoolean cancel ) + { + if (! (typeElement instanceof TypeElement )){ + return Collections.emptySet(); + } + Set result = new HashSet(); + result.add( (TypeElement) typeElement ); + + Set toProcess = new HashSet(); + toProcess.add((TypeElement) typeElement ); + while ( toProcess.size() >0 && !cancel.get()){ + TypeElement element = toProcess.iterator().next(); + toProcess.remove( element ); + Set set = doGetImplementors(modelImpl, element, cancel ); + if ( set.size() == 0 ){ + continue; + } + result.addAll( set ); + for (TypeElement impl : set) { + toProcess.add(impl); + } + } + return result; + } + + private DependencyInjectionResult createResult( VariableElement element, + TypeMirror elementType, Set types, Set productions ) + { + return new ResultImpl(element, elementType, types, productions, + getModel().getHelper() ); + } + + private void inspectHierarchy( Element productionElement, + TypeElement implementor, Set specializeElements , + WebBeansModelImplementation model ) + { + List enclosedElements = implementor.getEnclosedElements(); + for (Element enclosedElement : enclosedElements) { + if ( enclosedElement.getKind() != ElementKind.METHOD) { + continue; + } + if ( !productionElement.getSimpleName().contentEquals( + enclosedElement.getSimpleName())) + { + continue; + } + Set probableSpecializes = new HashSet(); + if ( collectSpecializes( productionElement , + (ExecutableElement)enclosedElement , model , + probableSpecializes , specializeElements)) + { + // for one method there could be just one override method in considered class + specializeElements.addAll( probableSpecializes ); + return; + } + } + } + + private boolean collectSpecializes( Element productionElement, + ExecutableElement element, WebBeansModelImplementation model, + Set probableSpecializes, Set specializeElements ) + { + ElementUtilities elementUtilities = + model.getHelper().getCompilationController().getElementUtilities(); + if ( !elementUtilities.overridesMethod(element)){ + return false; + } + ExecutableElement overriddenMethod = elementUtilities. + getOverriddenMethod( element); + if ( overriddenMethod == null ){ + return false; + } + if (!AnnotationObjectProvider.hasSpecializes(element, model.getHelper())){ + return false; + } + probableSpecializes.add( element); + if( overriddenMethod.equals( productionElement ) || + specializeElements.contains( productionElement)) + { + return true; + } + else { + return collectSpecializes(productionElement, overriddenMethod, model, + probableSpecializes, specializeElements); + } + } + + private static Set doGetImplementors( + WebBeansModelImplementation modelImpl, TypeElement typeElement, AtomicBoolean cancel ) + { + Set result = new HashSet(); + ElementHandle handle = ElementHandle.create(typeElement); + ClassIndex classIndex = modelImpl + .getHelper().getClasspathInfo().getClassIndex(); + if(cancel.get()) { + return Collections.emptySet(); + } + final Set> handles = classIndex + .getElements( + handle, + EnumSet.of(SearchKind.IMPLEMENTORS), + EnumSet.of(SearchScope.SOURCE, + SearchScope.DEPENDENCIES)); + if (handles == null) { + LOGGER.log(Level.WARNING, + "ClassIndex.getElements() was interrupted"); // NOI18N + return Collections.emptySet(); + } + for (ElementHandle elementHandle : handles) { + if(cancel.get()) { + return Collections.emptySet(); + } + LOGGER.log(Level.FINE, "found derived element {0}", + elementHandle.getQualifiedName()); // NOI18N + TypeElement derivedElement = elementHandle.resolve(modelImpl + .getHelper().getCompilationController()); + if (derivedElement == null) { + continue; + } + result.add(derivedElement); + } + return result; + } + + private void filterDefaultProductions( Set productionElements ) + { + DefaultBindingTypeFilter filter = DefaultBindingTypeFilter.get( + Element.class); + filter.init( getModel() ); + filter.filter( productionElements ); + } + + private Set getAllProductions( ){ + final Set result = new HashSet(); + try { + getModel().getHelper().getAnnotationScanner().findAnnotations( + PRODUCER_ANNOTATION, + EnumSet.of( ElementKind.FIELD, ElementKind.METHOD), + new AnnotationHandler() { + @Override + public void handleAnnotation( TypeElement type, + Element element,AnnotationMirror annotation ) + { + result.add( element ); + } + }); + } + catch (InterruptedException e) { + LOGGER.warning("Finding annotation "+PRODUCER_ANNOTATION+ + " was interrupted"); // NOI18N + } + return result; + } + + private void filterProductionByType( VariableElement element, + TypeMirror elementType, Set productionElements ) + { + TypeProductionFilter filter = TypeProductionFilter.get( ); + filter.init( elementType, element, getModel()); + filter.filter( productionElements ); + } + + private void filterBindingsByDefault( Set assignableTypes ){ + DefaultBindingTypeFilter filter = DefaultBindingTypeFilter.get( + TypeElement.class); + filter.init( getModel() ); + filter.filter( assignableTypes ); + } + + private void filterBindingByArchiveType(Set assignableTypes) { + ArchiveTypeBindingTypeFilter filter = ArchiveTypeBindingTypeFilter.get(TypeElement.class); + filter.init(getModel()); + filter.filter(assignableTypes); + } + + private Set getAssignableTypes( VariableElement element, + TypeMirror elementType, AtomicBoolean cancel ) + { + if (elementType.getKind() != TypeKind.DECLARED) { + return Collections.emptySet(); + } + Element typeElement = ((DeclaredType) elementType).asElement(); + if (!(typeElement instanceof TypeElement)) { + return Collections.emptySet(); + } + if (!((TypeElement) typeElement).getTypeParameters().isEmpty()) { + return getAssignables( elementType, (TypeElement)typeElement, + element, cancel ); + } + else { + Set implementors = getImplementors(getModel(), typeElement, cancel); + restrictedTypeFilter( implementors , (TypeElement)typeElement ); + return implementors; + } + } + + private void restrictedTypeFilter( Set allImplementors , + TypeElement originalElement ) { + RestrictedTypedFilter filter = new RestrictedTypedFilter(); + filter.init( originalElement , getModel()); + filter.filter( allImplementors ); + } + + private Set getAssignables( TypeMirror elementType, + TypeElement typeElement , VariableElement element, AtomicBoolean cancel) + { + Set result = getImplementors(getModel(), typeElement, cancel); + + // Now filter all found child classes according to real element type ( type mirror ) + TypeBindingFilter filter = TypeBindingFilter.get(); + filter.init( elementType, element, getModel() ); + filter.filter( result ); + return result; + } + + /* + * Method finds production elements which have appropriate binding types. + */ + private Set getProductions( + List qualifierAnnotations, AtomicBoolean cancel) + { + List> bindingCollections = + new ArrayList>( qualifierAnnotations.size()); + /* + * One need to handle special case with @Default annotation + * in case of specialization. There can be a case + * when production method doesn't explicitly declare @Default but + * specialize other method with several appropriate qualifiers. + * In this case original method will have @Default along with + * qualifiers "inherited" from specialized methods. + */ + boolean hasDefault = getModel().getHelper().getAnnotationsByType( + qualifierAnnotations ).get(DEFAULT_QUALIFIER_ANNOTATION) != null ; + Set currentBindings = new HashSet(); + for (AnnotationMirror annotationMirror : qualifierAnnotations) { + if(cancel.get()) { + currentBindings.clear(); + break; + } + DeclaredType type = annotationMirror.getAnnotationType(); + TypeElement annotationElement = (TypeElement)type.asElement(); + if ( annotationElement == null ){ + continue; + } + String annotationFQN = annotationElement.getQualifiedName().toString(); + findAnnotation( bindingCollections, annotationFQN , hasDefault, + currentBindings, cancel); + } + + if ( hasDefault ){ + bindingCollections.add( currentBindings ); + } + + Set result= null; + for ( int i=0; i list = bindingCollections.get(i); + if ( i==0 ){ + result = list; + } + else { + result.retainAll( list ); + } + } + if ( result == null ){ + return Collections.emptySet(); + } + return result; + } + + private void findAnnotation( final List> bindingCollections, + final String annotationFQN ,final boolean hasCurrent , + final Set currentBindings, + final AtomicBoolean cancel) + { + try { + final Set bindings = new HashSet(); + getModel().getHelper().getAnnotationScanner().findAnnotations( + annotationFQN, + EnumSet.of( ElementKind.FIELD, ElementKind.METHOD), + new AnnotationHandler() { + @Override + public void handleAnnotation( TypeElement type, + Element element,AnnotationMirror annotation ) + { + if (AnnotationObjectProvider.hasAnnotation( + element, PRODUCER_ANNOTATION, + getModel().getHelper())) + { + bindings.add(element); + bindings.addAll(getChildSpecializes( + element, getModel(), cancel)); + if (annotationFQN + .contentEquals(DEFAULT_QUALIFIER_ANNOTATION)) + { + currentBindings.addAll(bindings); + } + else { + bindingCollections.add(bindings); + } + } + } + }); + if ( hasCurrent ){ + for (Element element : bindings) { + if ( AnnotationObjectProvider.checkDefault( + element, getModel().getHelper())) + { + currentBindings.add( element ); + } + } + } + } + catch (InterruptedException e) { + LOGGER.warning("Finding annotation "+annotationFQN+ + " was interrupted"); // NOI18N + } + } + + /* + * Method finds type elements which have appropriate binding types. + */ + private Set getBindingTypes( List qualifierAnnotations ){ + List> bindingCollections = + new ArrayList>( qualifierAnnotations.size()); + + /* + * One need to handle special case with @Default annotation + * in case of specialization. There can be a case + * when bean doesn't explicitly declare @Default but + * specializes other beans with several appropriate qualifiers. + * In this case original bean will have @Default along with + * qualifiers "inherited" from specialized beans. + */ + boolean hasDefault = getModel().getHelper().getAnnotationsByType( + qualifierAnnotations ).get(DEFAULT_QUALIFIER_ANNOTATION) != null ; + Set defaultQualifiers = new HashSet(); + for (AnnotationMirror annotationMirror : qualifierAnnotations) { + DeclaredType type = annotationMirror.getAnnotationType(); + TypeElement annotationElement = (TypeElement) type.asElement(); + if ( annotationElement == null ){ + continue; + } + String annotationFQN = annotationElement.getQualifiedName() + .toString(); + PersistentObjectManager manager = getModel() + .getManager(annotationFQN); + Collection bindings = manager.getObjects(); + if (annotationFQN.contentEquals(DEFAULT_QUALIFIER_ANNOTATION)) { + defaultQualifiers.addAll(bindings); + } + else { + bindingCollections.add(new HashSet(bindings)); + if (hasDefault) { + for (BindingQualifier binding : bindings) { + if (AnnotationObjectProvider + .checkDefault(binding.getTypeElement(), + getModel().getHelper())) + { + defaultQualifiers.add(new BindingQualifier( + getModel().getHelper(), binding + .getTypeElement(), + DEFAULT_QUALIFIER_ANNOTATION)); + } + } + } + } + } + + if ( hasDefault ){ + bindingCollections.add( defaultQualifiers ); + } + + Set result= null; + for ( int i=0; i set = bindingCollections.get(i); + if ( i==0 ){ + result = set; + } + else { + result.retainAll( set ); + } + } + if ( result == null ){ + return Collections.emptySet(); + } + else { + Set set = new HashSet(); + for (BindingQualifier binding : result) { + set.add( binding.getTypeElement() ); + } + return set; + } + } + + protected static class InjectionPointDefinitionError extends Exception{ + private static final long serialVersionUID = -1568276063434281036L; + + private InjectionPointDefinitionError(String msg){ + super( msg ); + } + } + + protected static class DefinitionError extends Exception { + + private static final long serialVersionUID = 8538541504206293629L; + + protected DefinitionError( TypeElement element ){ + myElement = element; + } + + public TypeElement getElement(){ + return myElement; + } + + private TypeElement myElement; + } + private WebBeansModelImplementation myModel; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/Filter.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/Filter.java new file mode 100644 index 000000000000..dd6fcb78f616 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/Filter.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + + +/** + * @author ads + * + */ +abstract class Filter { + + void filter( Set set ){ + } + + static void assertElement( Class clazz ){ + assert clazz.equals( Element.class ) || clazz.equals( TypeElement.class ); + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/InterceptorBindingChecker.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/InterceptorBindingChecker.java new file mode 100644 index 000000000000..4482fdab3f0d --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/InterceptorBindingChecker.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.lang.annotation.ElementType; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.InterceptorBindingVerifier; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.TargetVerifier; + + +/** + * @author ads + * + */ +class InterceptorBindingChecker extends RuntimeAnnotationChecker { + + static final String INTERCEPTOR_BINDING = "jakarta.interceptor.InterceptorBinding"; // NOI18N + + InterceptorBindingChecker(AnnotationModelHelper helper){ + init( null, helper ); + } + + void init(TypeElement element){ + init( element , getHelper() ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.RuntimeAnnotationChecker#getLogger() + */ + @Override + protected Logger getLogger() { + return Logger.getLogger(InterceptorBindingChecker.class.getName()); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.RuntimeAnnotationChecker#getAnnotation() + */ + @Override + protected String getAnnotation() { + return INTERCEPTOR_BINDING; + } + + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.TargetAnalyzer#hasReqiredTarget(javax.lang.model.element.AnnotationMirror, java.util.Set) + */ + @Override + public boolean hasReqiredTarget( AnnotationMirror target, + Set set ) + { + boolean hasRequiredTarget = super.hasReqiredTarget(target, set); + if (!hasRequiredTarget) { + getLogger().log(Level.WARNING, + "Annotation "+getElement().getQualifiedName()+ + "declared as Interceptor Binding but has wrong target values." + + " Correct target values are {METHOD, TYPE} or" + + " or TYPE ");// NOI18N + } + return hasRequiredTarget; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.annotation.TargetAnalyzer#getTargetVerifier() + */ + @Override + protected TargetVerifier getTargetVerifier() { + return InterceptorBindingVerifier.getInstance(); + } + + void clean() { + init( null , getHelper() ); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/InterceptorObject.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/InterceptorObject.java new file mode 100644 index 000000000000..74a14a6c9796 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/InterceptorObject.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.List; +import java.util.Map; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.PersistentObject; +import org.netbeans.modules.jakarta.web.beans.impl.model.AbstractObjectProvider.Refreshable; + + +/** + * @author ads + * + */ +class InterceptorObject extends PersistentObject implements Refreshable { + + static final String INTERCEPTOR = "jakarta.interceptor.Interceptor"; // NOI18N + + InterceptorObject( AnnotationModelHelper helper, + TypeElement typeElement ) + { + super(helper, typeElement); + boolean valid = refresh(typeElement); + assert valid; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractObjectProvider.Refreshable#refresh(javax.lang.model.element.TypeElement) + */ + @Override + public boolean refresh( TypeElement type ) { + List allAnnotationMirrors = + getHelper().getCompilationController().getElements(). + getAllAnnotationMirrors(type); + Map annotationsByType = + getHelper().getAnnotationsByType( allAnnotationMirrors ); + return annotationsByType.get( INTERCEPTOR ) != null ; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/InterceptorObjectProvider.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/InterceptorObjectProvider.java new file mode 100644 index 000000000000..d01ca7bbf3fe --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/InterceptorObjectProvider.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; + + +/** + * @author ads + * + */ +class InterceptorObjectProvider extends AbstractObjectProvider { + + InterceptorObjectProvider( AnnotationModelHelper helper ) + { + super(InterceptorObject.INTERCEPTOR, helper); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractObjectProvider#createTypeElement(javax.lang.model.element.TypeElement) + */ + @Override + protected InterceptorObject createTypeElement( TypeElement element ) { + return new InterceptorObject(getHelper(), element); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/MemberBindingFilter.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/MemberBindingFilter.java new file mode 100644 index 000000000000..ae7ac89cb73a --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/MemberBindingFilter.java @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Name; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; + + +/** + * @author ads + * + */ +class MemberBindingFilter extends Filter { + + private static final String NON_BINDING_MEMBER_ANNOTATION = + "jakarta.enterprise.util.Nonbinding"; // NOI18N + + private MemberBindingFilter( Class clazz ){ + myClass = clazz; + } + + static MemberBindingFilter get( Class clazz ) { + assertElement(clazz); + // could be changed to cached ThreadLocal variable + if ( clazz.equals( Element.class )){ + return (MemberBindingFilter) new MemberBindingFilter( + Element.class); + } + else if ( clazz.equals( TypeElement.class ) ){ + return (MemberBindingFilter)new MemberBindingFilter( + TypeElement.class); + } + return null; + } + + void init( Collection bindingAnnotations, + WebBeansModelImplementation impl ) + { + myImpl = impl; + myBindingAnnotations = bindingAnnotations; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.TypeFilter#filter(java.util.Set) + */ + void filter( Set set ) { + super.filter(set); + if ( set.size() == 0 ){ + return; + } + /* + * Binding annotation could have members. See example : + * @BindingType + * @Retention(RUNTIME) + * @Target({METHOD, FIELD, PARAMETER, TYPE}) + * public @interface PayBy { + * PaymentMethod value(); + * @NonBinding String comment(); + * } + * One need to check presence of member in binding annotation at + * injected point and compare this member with member in annotation + * for discovered type. + * Members with @Nonbinding annotation should be ignored. + */ + for (AnnotationMirror annotation : getBindingAnnotations()) { + Map + elementValues = annotation.getElementValues(); + Set bindingMembers = collectBindingMembers( + annotation , getImplementation() ); + checkMembers(elementValues, bindingMembers, set ); + } + } + + Class getElementClass(){ + return myClass; + } + + private void checkMembers( + Map elementValues, + Set members, Set set ) + { + MemberCheckerFilter filter = MemberCheckerFilter.get( getElementClass()); + filter.init( elementValues , members, getImplementation()); + filter.filter(set); + } + + + static Set collectBindingMembers( AnnotationMirror annotation , + WebBeansModelImplementation impl ) + { + DeclaredType annotationType = annotation.getAnnotationType(); + TypeElement annotationElement = (TypeElement)annotationType.asElement(); + List members = annotationElement.getEnclosedElements(); + Set bindingMembers = new HashSet(); + for (Element member : members) { + if ( member instanceof ExecutableElement ){ + ExecutableElement exec = (ExecutableElement)member; + if ( isBindingMember( exec , impl )){ + bindingMembers.add( exec ); + } + } + } + return bindingMembers; + } + + private static boolean isBindingMember( ExecutableElement element , + WebBeansModelImplementation impl ) + { + List annotationMirrors = + impl.getHelper().getCompilationController().getElements(). + getAllAnnotationMirrors( element); + for (AnnotationMirror annotationMirror : annotationMirrors) { + TypeElement annotation = (TypeElement)annotationMirror. + getAnnotationType().asElement(); + if ( annotation == null ){ + continue; + } + Name name = annotation.getQualifiedName(); + if ( NON_BINDING_MEMBER_ANNOTATION.contentEquals(name)){ + return false; + } + } + return true; + } + + private WebBeansModelImplementation getImplementation(){ + return myImpl; + } + + private Collection getBindingAnnotations(){ + return myBindingAnnotations; + } + + private WebBeansModelImplementation myImpl; + private Collection myBindingAnnotations; + private Class myClass; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/MemberCheckerFilter.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/MemberCheckerFilter.java new file mode 100644 index 000000000000..80b2f5b11cb1 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/MemberCheckerFilter.java @@ -0,0 +1,245 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; +import org.netbeans.modules.jakarta.web.beans.impl.model.AnnotationObjectProvider.SpecializeVisitor; + + +/** + * @author ads + * + */ +class MemberCheckerFilter extends Filter { + + private MemberCheckerFilter( Class clazz ){ + myClass = clazz; + } + + public static MemberCheckerFilter get(Class clazz) { + assertElement( clazz ); + // could be changed to ThreadLocal cached access + if ( clazz.equals( Element.class)) { + return (MemberCheckerFilter) new MemberCheckerFilter( + Element.class); + } + else if ( clazz.equals( TypeElement.class)){ + return (MemberCheckerFilter) new MemberCheckerFilter( + TypeElement.class); + } + return null; + } + + void init( Map + elementValues, Set members, + WebBeansModelImplementation impl ) + { + myImpl = impl; + myValues = elementValues; + myMembers = members; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.TypeFilter#filter(java.util.Set) + */ + @Override + void filter( Set set ) { + super.filter(set); + for( Entry entry : + getValues().entrySet()) + { + ExecutableElement execElement = entry.getKey(); + AnnotationValue value = entry.getValue(); + if ( getMembers().contains( execElement )) { + checkMember( execElement, value, set ); + } + } + } + + Class getElementClass(){ + return myClass; + } + + static Element getSpecialized( ExecutableElement productionElement, + WebBeansModelImplementation model , String annotationName ) + { + return getSpecialized(productionElement, model.getHelper(), annotationName); + } + + static void visitSpecializes( ExecutableElement method, + AnnotationModelHelper helper , SpecializeVisitor visitor ) + { + ExecutableElement current = method; + while ( true ){ + ExecutableElement overridenElement = helper.getCompilationController(). + getElementUtilities().getOverriddenMethod( current); + if ( overridenElement != null && AnnotationObjectProvider.hasSpecializes( + current, helper)) + { + if ( visitor.visit(overridenElement)){ + return; + } + current = overridenElement; + } + else { + break; + } + } + } + + static Element getSpecialized( ExecutableElement productionElement, + final AnnotationModelHelper helper , final String annotationName ) + { + final Element result[] = new Element[1]; + SpecializeVisitor visitor = new SpecializeVisitor() { + + @Override + public boolean visit( ExecutableElement overridenElement ) { + if ( FieldInjectionPointLogic.DEFAULT_QUALIFIER_ANNOTATION. + equals( annotationName)) + { + if ( AnnotationObjectProvider.checkSpecializedDefault( + overridenElement, helper)) + { + result[0] = overridenElement; + return true; + } + } + else if ( AnnotationObjectProvider. + hasAnnotation( overridenElement, annotationName, + helper)) + { + result[0] = overridenElement; + return true; + } + return false; + } + + @Override + public boolean visit( TypeElement superElement ) { + return false; + } + }; + visitSpecializes( productionElement , helper, visitor); + return result[0]; + } + + private void checkMember( ExecutableElement exec, AnnotationValue value, + Set elementsWithBindings ) + { + Element annotationElement = exec.getEnclosingElement(); + if ( !( annotationElement instanceof TypeElement ) ){ + return; + } + String annotationName = ((TypeElement)annotationElement). + getQualifiedName().toString(); + // annotation member should be checked for presence at Binding type + for (Iterator iterator = elementsWithBindings.iterator(); + iterator.hasNext(); ) + { + Element element = iterator.next(); + if ( !checkMember(exec, value, element, iterator , annotationName)) + { + // check specializes.... + if (element instanceof TypeElement) { + TypeElement specializedSuper = AnnotationObjectProvider + .checkSuper((TypeElement) element, annotationName, + getImplementation().getHelper()); + if (specializedSuper != null) { + checkMember(exec, value, specializedSuper, iterator, + annotationName); + } + } + else if ( element instanceof ExecutableElement){ + Element specialized = getSpecialized((ExecutableElement)element, + getImplementation(), annotationName ); + if ( specialized != null ){ + checkMember(exec, value, specialized, iterator, + annotationName); + } + } + } + } + } + + private boolean checkMember( ExecutableElement exec, AnnotationValue value, + Element elementWithBinding, Iterator iterator, + String annotationName ) + { + List allAnnotationMirrors = getImplementation() + .getHelper().getCompilationController().getElements() + .getAllAnnotationMirrors(elementWithBinding); + AnnotationMirror annotationMirror = getImplementation().getHelper() + .getAnnotationsByType(allAnnotationMirrors).get(annotationName); + if ( annotationMirror == null ){ + return false; + } + Map + elementValues = annotationMirror.getElementValues(); + AnnotationValue valueForType = elementValues.get(exec); + if (!equals(value, valueForType)) { + iterator.remove(); + } + return true; + } + + static boolean equals( AnnotationValue value1 , AnnotationValue value2 ){ + if ( value1== null ){ + return value2 == null; + } + else { + if ( value1.getValue() == null ){ + return value2!= null && value2.getValue()==null; + } + else { + return value1.getValue().equals( value2 == null ? null : value2.getValue()); + } + } + } + + private WebBeansModelImplementation getImplementation(){ + return myImpl; + } + + private Map getValues(){ + return myValues; + } + + private Set getMembers(){ + return myMembers; + } + + private WebBeansModelImplementation myImpl; + private Map myValues; + private Set myMembers; + private Class myClass; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/MultiLookupStrategy.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/MultiLookupStrategy.java new file mode 100644 index 000000000000..fce5d52e6808 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/MultiLookupStrategy.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.concurrent.atomic.AtomicBoolean; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.impl.model.results.ResultImpl; + + +/** + * @author ads + * + */ +public class MultiLookupStrategy extends SingleResultLookupStrategy { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.ResultLookupStrategy#getType(org.netbeans.modules.jakarta.web.beans.impl.model.WebBeansModelImplementation, javax.lang.model.type.DeclaredType, javax.lang.model.element.VariableElement) + */ + @Override + public TypeMirror getType( WebBeansModelImplementation model, + DeclaredType parent, VariableElement element ) + { + return ParameterInjectionPointLogic.getParameterType( + model.getHelper().getCompilationController(), element , parent , + FieldInjectionPointLogic.INSTANCE_INTERFACE); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.ResultLookupStrategy#getType(org.netbeans.modules.jakarta.web.beans.impl.model.WebBeansModelImplementation, javax.lang.model.type.TypeMirror) + */ + @Override + public TypeMirror getType( WebBeansModelImplementation model, + TypeMirror typeMirror ) { + return ParameterInjectionPointLogic.getParameterType( + typeMirror , FieldInjectionPointLogic.INSTANCE_INTERFACE ); + } + + @Override + protected DependencyInjectionResult filterEnabled( DependencyInjectionResult result, + WebBeansModelImplementation model, AtomicBoolean cancel) + { + if ( result instanceof ResultImpl ){ + EnableBeansFilter filter = new EnableBeansFilter((ResultImpl)result, + model , true ); + return filter.filter(cancel); + } + return result; + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/NamedStereotype.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/NamedStereotype.java new file mode 100644 index 000000000000..0aae1243b636 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/NamedStereotype.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.List; +import java.util.Map; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.PersistentObject; +import org.netbeans.modules.jakarta.web.beans.impl.model.AbstractObjectProvider.Refreshable; + + +/** + * @author ads + * + */ +class NamedStereotype extends PersistentObject implements Refreshable{ + + public NamedStereotype( AnnotationModelHelper helper, + TypeElement typeElement ) + { + super(helper, typeElement); + boolean valid = refresh( typeElement); + assert valid; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractObjectProvider.Refreshable#refresh(javax.lang.model.element.TypeElement) + */ + @Override + public boolean refresh( TypeElement type ) { + List allAnnotationMirrors = + getHelper().getCompilationController().getElements(). + getAllAnnotationMirrors(type); + Map annotationsByType = + getHelper().getAnnotationsByType( allAnnotationMirrors ); + boolean isStereotype = annotationsByType.get( + StereotypeChecker.STEREOTYPE) != null ; + if ( !isStereotype ){ + return false; + } + boolean hasNamed = NamedStereotypeObjectProvider.hasNamed(type, + getHelper()); + return hasNamed; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/NamedStereotypeObjectProvider.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/NamedStereotypeObjectProvider.java new file mode 100644 index 000000000000..efb20d624c08 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/NamedStereotypeObjectProvider.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.Collections; +import java.util.EnumSet; +import java.util.LinkedList; +import java.util.List; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationHandler; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; + + +/** + * @author ads + * + */ +class NamedStereotypeObjectProvider extends AbstractObjectProvider { + + NamedStereotypeObjectProvider(AnnotationModelHelper helper){ + super( StereotypeChecker.STEREOTYPE, helper ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractObjectProvider#createInitialObjects() + */ + @Override + public List createInitialObjects() + throws InterruptedException + { + final List result = new LinkedList(); + getHelper().getAnnotationScanner().findAnnotations( + getAnnotation(), + EnumSet.of(ElementKind.ANNOTATION_TYPE), + new AnnotationHandler() { + @Override + public void handleAnnotation(TypeElement type, + Element element, AnnotationMirror annotation) + { + if ( hasNamed( type , getHelper() )) { + result.add(createTypeElement(type)); + } + } + }); + return result; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractObjectProvider#createObjects(javax.lang.model.element.TypeElement) + */ + @Override + public List createObjects( TypeElement type ) { + if (type.getKind() == ElementKind.ANNOTATION_TYPE && + getHelper().hasAnnotation(type.getAnnotationMirrors(), + getAnnotation())) + { + if ( hasNamed(type, getHelper())){ + return Collections.singletonList(createTypeElement(type)); + } + } + return Collections.emptyList(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractObjectProvider#createTypeElement(javax.lang.model.element.TypeElement) + */ + @Override + protected NamedStereotype createTypeElement( TypeElement element ) { + return new NamedStereotype(getHelper(), element); + } + + static boolean hasNamed( TypeElement type , AnnotationModelHelper helper ) { + if (AnnotationObjectProvider.hasAnnotation(type, + FieldInjectionPointLogic.NAMED_QUALIFIER_ANNOTATION, helper)) + { + return true; + } + List stereotypes = WebBeansModelProviderImpl. + getAllStereotypes(type, helper.getHelper()); + for (AnnotationMirror annotationMirror : stereotypes) { + TypeElement annotation = (TypeElement)annotationMirror. + getAnnotationType().asElement(); + if (annotation!= null && AnnotationObjectProvider.hasAnnotation(annotation, + FieldInjectionPointLogic.NAMED_QUALIFIER_ANNOTATION, helper)) + { + return true; + } + } + + return false; + } + +} \ No newline at end of file diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/NormalScopeChecker.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/NormalScopeChecker.java new file mode 100644 index 000000000000..c09e720bb322 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/NormalScopeChecker.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + + + + +/** + * @author ads + * + */ +class NormalScopeChecker extends ScopeChecker { + + static NormalScopeChecker get(){ + return new NormalScopeChecker(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.ScopeChecker#getAnnotation() + */ + @Override + protected String getAnnotation() { + return NORMAL_SCOPE; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/PackagingFilter.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/PackagingFilter.java new file mode 100644 index 000000000000..1cc215bb435b --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/PackagingFilter.java @@ -0,0 +1,149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.Collection; +import java.util.Iterator; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; + +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.java.source.ClasspathInfo; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.ElementUtilities; +import org.netbeans.api.java.source.SourceUtils; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; + + + +/** + * @author ads + * + */ +class PackagingFilter { + + PackagingFilter(WebBeansModelImplementation model){ + myModel = model; + } + + void filter(Collection collection, AtomicBoolean cancel ){ + for (Iterator iterator = collection.iterator(); + iterator.hasNext(); ) + { + if(cancel.get()) { + break; + } + Element element = iterator.next(); + if ( remove(element, cancel)){ + iterator.remove(); + } + } + } + + void filterTypes(Collection collection, AtomicBoolean cancel ){ + for (Iterator iterator = collection.iterator(); + iterator.hasNext(); ) + { + DeclaredType type = iterator.next(); + Element element = getModel().getHelper().getCompilationController(). + getTypes().asElement( type ); + if ( element != null && remove(element, cancel)){ + iterator.remove(); + } + } + } + + private boolean remove( Element element, AtomicBoolean cancel ){ + TypeElement typeElement; + if ( element instanceof TypeElement ){ + typeElement = (TypeElement) element; + } + else { + typeElement = getModel().getHelper().getCompilationController(). + getElementUtilities().enclosingTypeElement(element); + } + if ( typeElement == null || cancel.get()){ + return false; + } + + FileObject file = SourceUtils.getFile(ElementHandle.create(typeElement), + ClasspathInfo.create(getModel().getModelUnit().getBootPath() , + ClassPath.EMPTY, getModel().getModelUnit().getSourcePath())); + + if ( file != null || cancel.get()){ + return false; + } + + PackageElement pack = getModel().getHelper().getCompilationController(). + getElements().getPackageOf( typeElement ); + if ( pack == null || cancel.get()){ + return false; + } + String packageName = pack.getQualifiedName().toString(); + String fqn = ElementUtilities.getBinaryName(typeElement); + String className = fqn.substring(packageName.length()); + if ( className.length() >0 && className.charAt(0)=='.' ){ + className = className.substring(1); + } + else { + return false; + } + int dotIndex = className.indexOf('.'); + if ( dotIndex != -1 ){ + className = className.substring( 0, dotIndex ); + } + if ( className == null || cancel.get()){ + return false; + } + + String path = packageName.replace('.', '/')+'/'+className+".class"; // NOI18N + ClassPath classPath = getModel().getModelUnit().getCompilePath(); + FileObject resource = classPath.findResource( path ); + if ( resource != null && !cancel.get()){ + FileObject root = classPath.findOwnerRoot( resource ); + if ( root == null || cancel.get()){ + return false; + } + if ( FileUtil.isArchiveFile( root ) && !cancel.get()){ + FileObject archiveFile = FileUtil.getArchiveFile(root); + String ext = archiveFile.getExt(); + if ( "war".equalsIgnoreCase( ext)){ // NOI18N + return root.getFileObject("WEB-INF/beans.xml") == null; // NOI18N + } + } + return !hasMetaBeans(root); + } + return false; + } + + private boolean hasMetaBeans(FileObject root ){ + return root.getFileObject("META-INF/beans.xml") != null; // NOI18N + } + + private WebBeansModelImplementation getModel(){ + return myModel; + } + + private WebBeansModelImplementation myModel; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/ParameterInjectionPointLogic.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/ParameterInjectionPointLogic.java new file mode 100644 index 000000000000..4de619f39397 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/ParameterInjectionPointLogic.java @@ -0,0 +1,327 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; +import org.netbeans.modules.jakarta.web.beans.api.model.CdiException; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.impl.model.results.DefinitionErrorResult; +import org.netbeans.modules.jakarta.web.beans.impl.model.results.ResultImpl; +import org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +abstract class ParameterInjectionPointLogic extends FieldInjectionPointLogic + implements WebBeansModelProvider +{ + + static final String CONTEXT_DEPENDENT_ANNOTATION = + "jakarta.enterprise.context.Dependent"; // NOI18N + + static final String DISPOSES_ANNOTATION = + "jakarta.enterprise.inject.Disposes"; // NOI18N + + static final String OBSERVES_ANNOTATION = + "jakarta.enterprise.event.Observes"; // NOI18N + + + ParameterInjectionPointLogic( WebBeansModelImplementation model ) { + super( model ); + } + + protected DependencyInjectionResult findParameterInjectable( VariableElement element , + DeclaredType parentType , ResultLookupStrategy strategy, AtomicBoolean cancel ) + { + DeclaredType parent = parentType; + try { + parent = getParent(element, parentType); + } + catch (DefinitionError e) { + TypeElement type = e.getElement(); + return new DefinitionErrorResult(element, parentType, + NbBundle.getMessage(WebBeansModelProviderImpl.class, + "ERR_BadParent", element.getSimpleName(), + type!= null? type.toString(): null)); + } + + ExecutableElement parentMethod = (ExecutableElement)element. + getEnclosingElement(); + ExecutableType methodType = (ExecutableType)getCompilationController(). + getTypes().asMemberOf(parent, parentMethod ); + List parameterTypes = methodType.getParameterTypes(); + + boolean isInjectionPoint = false; + /* + * Check if method has parameters as injection points. + * F.e. disposer method has only one parameter with @Disposes annotation. + * All other its parameters are injection points. + */ + List parameters = parentMethod.getParameters(); + int index =0; + for (int i=0; i productions = ((ResultImpl) result).getProductions(); + TypeElement enclosingTypeElement = getCompilationController(). + getElementUtilities().enclosingTypeElement(element); + for (Iterator iterator = productions.iterator(); + iterator.hasNext(); ) + { + Element injectable = iterator.next(); + if ( !(injectable instanceof ExecutableElement) || + !getCompilationController().getElementUtilities(). + isMemberOf( injectable, enclosingTypeElement)) + { + iterator.remove(); + } + } + } + else { + return result; + } + } + + if ( isInjectionPoint ){ + return strategy.getResult(getModel(), result, cancel ); + } + else { + return new DefinitionErrorResult(element, elementType, + NbBundle.getMessage( WebBeansModelProviderImpl.class, + "ERR_NoInjectPoint" , element.getSimpleName())); + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider#isDynamicInjectionPoint(javax.lang.model.element.VariableElement) + */ + @Override + public boolean isDynamicInjectionPoint( VariableElement element ) { + TypeMirror type = getParameterType(element, null, INSTANCE_INTERFACE); + if ( type != null ){ + try { + return isInjectionPoint(element); + } + catch ( org.netbeans.modules.jakarta.web.beans.api.model. + InjectionPointDefinitionError e ) + { + return false; + } + } + return false; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.Result.ResolutionResult#getScope(javax.lang.model.element.Element) + */ + @Override + public String getScope( Element element ) throws CdiException { + return getScope(element , getModel().getHelper()); + } + + public static String getScope( Element element, AnnotationModelHelper helper ) + throws CdiException + { + String scope = getDeclaredScope(element, helper); + if (scope != null) { + return scope; + } + List stereotypes = WebBeansModelProviderImpl + .getAllStereotypes(element, helper.getHelper()); + for (AnnotationMirror annotationMirror : stereotypes) { + DeclaredType annotationType = annotationMirror.getAnnotationType(); + Element annotationElement = annotationType.asElement(); + if ( annotationElement == null ){ + continue; + } + String declaredScope = getDeclaredScope(annotationElement, helper); + if (declaredScope == null) { + continue; + } + if (scope == null) { + scope = declaredScope; + } + else if (!scope.equals(declaredScope)) { + throw new CdiException(NbBundle.getMessage(ParameterInjectionPointLogic.class, + "ERR_DefaultScopeCollision", scope, declaredScope)); // NOI18N + } + } + if (scope != null) { + return scope; + } + return CONTEXT_DEPENDENT_ANNOTATION; + } + + static String getDeclaredScope( Element element , + AnnotationModelHelper helper ) throws CdiException + { + List annotationMirrors = element.getAnnotationMirrors(); + ScopeChecker scopeChecker = ScopeChecker.get(); + NormalScopeChecker normalScopeChecker = NormalScopeChecker.get(); + String scope = getDeclaredScope(helper, annotationMirrors, scopeChecker, + normalScopeChecker, true); + if ( scope != null ){ + return scope; + } + + annotationMirrors = helper.getCompilationController().getElements(). + getAllAnnotationMirrors( element ); + return getDeclaredScope(helper, annotationMirrors, scopeChecker, + normalScopeChecker, false ); + } + + private static String getDeclaredScope( AnnotationModelHelper helper, + List annotationMirrors, + ScopeChecker scopeChecker , NormalScopeChecker normalScopeChecker , + boolean singleScopeRequired ) throws CdiException + { + List annotations = annotationMirrors; + if ( !singleScopeRequired ){ + annotations = new ArrayList( + annotationMirrors); + Collections.reverse( annotations ); + } + String scope = null; + for (AnnotationMirror annotationMirror : annotations ) { + String declaredScope = null; + DeclaredType annotationType = annotationMirror.getAnnotationType(); + Element annotationElement = annotationType.asElement(); + if ( annotationElement instanceof TypeElement ){ + TypeElement annotation = (TypeElement)annotationElement; + scopeChecker.init(annotation, helper ); + if ( scopeChecker.check() ){ + declaredScope = annotation.getQualifiedName().toString(); + } + normalScopeChecker.init( annotation, helper ); + if ( normalScopeChecker.check() ){ + declaredScope = annotation.getQualifiedName().toString(); + } + if ( declaredScope != null ){ + if ( !singleScopeRequired ){ + return declaredScope; + } + if ( scope != null ){ + throw new CdiException(NbBundle.getMessage( + ParameterInjectionPointLogic.class, + "ERR_SeveralScopes")); // NOI18N + } + else { + scope = declaredScope; + } + } + } + } + return scope; + } + + protected TypeMirror getParameterType( Element element , DeclaredType parentType, + String... interfaceFqns) + { + return getParameterType(getCompilationController(), + element, parentType, interfaceFqns); + } + + static TypeMirror getParameterType( CompilationController controller, + Element element , DeclaredType parentType, String... interfaceFqns) + { + TypeMirror elementType = null; + if ( parentType == null ) { + elementType = element.asType(); + } + else { + elementType = controller.getTypes().asMemberOf(parentType, element); + } + return getParameterType(elementType,interfaceFqns); + } + + static TypeMirror getParameterType( TypeMirror elementType, + String... interfaceFqns ) + { + if ( elementType instanceof DeclaredType ){ + DeclaredType declaredType = (DeclaredType)elementType; + Element elementDeclaredType = declaredType.asElement(); + if ( elementDeclaredType!= null && + elementDeclaredType.getKind() == ElementKind.INTERFACE ) + { + String typeFqn = ((TypeElement)elementDeclaredType). + getQualifiedName().toString(); + for (String interfaceFqn : interfaceFqns) { + if (interfaceFqn.equals(typeFqn)) { + List typeArguments = declaredType + .getTypeArguments(); + if (typeArguments.size() > 0) { + return typeArguments.get(0); + } + } + } + } + } + return null; + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/QualifierChecker.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/QualifierChecker.java new file mode 100644 index 000000000000..ab6bd2664fce --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/QualifierChecker.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.lang.annotation.ElementType; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.AnnotationMirror; + +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.QualifierVerifier; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.TargetVerifier; + + +/** + * @author ads + * + */ +class QualifierChecker extends RuntimeAnnotationChecker implements Checker { + + private static final String QUALIFIER_TYPE_ANNOTATION= + "jakarta.inject.Qualifier"; // NOI18N + + QualifierChecker(){ + this( false ); + } + + QualifierChecker( boolean event ){ + isEvent = event; + } + + static QualifierChecker get() { + // could be changed to cached ThreadLocal access + return new QualifierChecker(); + } + + static QualifierChecker get(boolean event) { + // could be changed to cached ThreadLocal access + return new QualifierChecker(event); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.Checker#check() + */ + @Override + public boolean check() { + if ( BUILT_IN_QUALIFIERS.contains( getElement().getQualifiedName().toString())){ + return true; + } + else { + return super.check(); + } + } + + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.RuntimeAnnotationChecker#getAnnotation() + */ + @Override + protected String getAnnotation() { + return QUALIFIER_TYPE_ANNOTATION; + } + + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.RuntimeAnnotationChecker#getLogger() + */ + @Override + protected Logger getLogger() { + return FieldInjectionPointLogic.LOGGER; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.TargetAnalyzer#hasReqiredTarget(javax.lang.model.element.AnnotationMirror, java.util.Set) + */ + @Override + public boolean hasReqiredTarget( AnnotationMirror target, + Set set ) + { + boolean hasRequiredTarget = super.hasReqiredTarget(target, set); + if (!hasRequiredTarget) { + if ( isEvent ) { + getLogger().log(Level.WARNING, "Annotation " + + getElement().getQualifiedName() + + "declared as Qualifier but has wrong target values." + + " Correct target values are {METHOD, FIELD, PARAMETER, TYPE}" + + " or {FIELD, PARAMETER}");// NOI18N + } + else { + getLogger().log(Level.WARNING, "Annotation " + + getElement().getQualifiedName() + + "declared as Qualifier but has wrong target values." + + " Correct target values are {METHOD, FIELD, PARAMETER, TYPE}");// NOI18N + } + } + return hasRequiredTarget; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.annotation.TargetAnalyzer#getTargetVerifier() + */ + @Override + protected TargetVerifier getTargetVerifier() { + return QualifierVerifier.getInstance( isEvent ); + } + + private static final Set BUILT_IN_QUALIFIERS = new HashSet(); + + static { + BUILT_IN_QUALIFIERS.add(WebBeansModelProviderImpl.ANY_QUALIFIER_ANNOTATION); + BUILT_IN_QUALIFIERS.add(WebBeansModelProviderImpl.NEW_QUALIFIER_ANNOTATION); + BUILT_IN_QUALIFIERS.add(WebBeansModelProviderImpl.DEFAULT_QUALIFIER_ANNOTATION); + BUILT_IN_QUALIFIERS.add(WebBeansModelProviderImpl.NAMED_QUALIFIER_ANNOTATION); + } + + private boolean isEvent; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/RestrictedTypedFilter.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/RestrictedTypedFilter.java new file mode 100644 index 000000000000..c89e36e67808 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/RestrictedTypedFilter.java @@ -0,0 +1,140 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Types; + + +/** + * @author ads + * + */ +public class RestrictedTypedFilter extends Filter { + + @Override + void filter( Set elements ){ + Set allImplementors = new HashSet( elements ); + for (Iterator iterator = allImplementors.iterator() ; + iterator.hasNext() ; ) + { + TypeElement typeElement = iterator.next(); + Collection restrictedTypes = getRestrictedTypes(typeElement, + getImplementation()); + if ( restrictedTypes == null ){ + continue; + } + boolean hasBeanType = false; + TypeElement element = getElement(); + TypeMirror type = element.asType(); + Types types= getImplementation().getHelper().getCompilationController(). + getTypes(); + for (TypeMirror restrictedType : restrictedTypes) { + if ( types.isSameType( types.erasure( type), + types.erasure( restrictedType))) + { + hasBeanType = true; + break; + } + } + if ( !hasBeanType ){ + iterator.remove(); + } + } + } + + static Collection getRestrictedTypes( Element element , + WebBeansModelImplementation implementation ) + { + if ( element == null ){ + return null; + } + List annotationMirrors = + element.getAnnotationMirrors(); + Map annotations = + implementation.getHelper().getAnnotationsByType( annotationMirrors ); + AnnotationMirror typedAnnotation = annotations.get( + WebBeansModelProviderImpl.TYPED_RESTRICTION ); + if ( typedAnnotation == null ){ + return null; + } + Map elementValues = + typedAnnotation.getElementValues(); + if ( elementValues == null ){ + return Collections.emptyList(); + } + AnnotationValue restrictedTypes = null; + for( Entry entry: + elementValues.entrySet()) + { + ExecutableElement key = entry.getKey(); + AnnotationValue value = entry.getValue(); + if ( key.getSimpleName().contentEquals("value")){ // NOI18N + restrictedTypes = value; + break; + } + } + if ( restrictedTypes == null ){ + return Collections.emptyList(); + } + Object value = restrictedTypes.getValue(); + Collection result = new LinkedList(); + if ( value instanceof List ){ + for( Object type : (List)value){ + AnnotationValue annotationValue = (AnnotationValue)type; + type = annotationValue.getValue(); + if (type instanceof TypeMirror){ + result.add((TypeMirror) type ); + } + } + } + return result; + } + + void init( TypeElement element, WebBeansModelImplementation modelImpl ) { + myImpl = modelImpl; + myElement = element; + } + + private WebBeansModelImplementation getImplementation() { + return myImpl; + } + + private TypeElement getElement(){ + return myElement; + } + + private TypeElement myElement; + private WebBeansModelImplementation myImpl; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/ResultLookupStrategy.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/ResultLookupStrategy.java new file mode 100644 index 000000000000..5da62a8c4384 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/ResultLookupStrategy.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.concurrent.atomic.AtomicBoolean; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; + + +/** + * @author ads + * + */ +public interface ResultLookupStrategy { + + ResultLookupStrategy SINGLE_LOOKUP_STRATEGY = new SingleResultLookupStrategy(); + + ResultLookupStrategy MULTI_LOOKUP_STRATEGY = new MultiLookupStrategy(); + + DependencyInjectionResult getResult(WebBeansModelImplementation model, DependencyInjectionResult result, AtomicBoolean cancel ); + + TypeMirror getType( WebBeansModelImplementation model, + DeclaredType parent, VariableElement element); + + TypeMirror getType( WebBeansModelImplementation model, TypeMirror typeMirror ); + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/RuntimeAnnotationChecker.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/RuntimeAnnotationChecker.java new file mode 100644 index 000000000000..79ed52db7f51 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/RuntimeAnnotationChecker.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.lang.annotation.RetentionPolicy; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.TargetAnalyzer; + + +/** + * @author ads + * + */ +public abstract class RuntimeAnnotationChecker extends TargetAnalyzer { + + protected static final String VALUE = "value"; // NOI18N + + public void init( TypeElement element, AnnotationModelHelper helper ) { + init( (Element)element , helper.getHelper() ); + } + + public boolean check() { + List annotations = getElement() + .getAnnotationMirrors(); + boolean hasAnnotation = getHelper().hasAnnotation(annotations, + getAnnotation()); + + if (!hasAnnotation) { + // this is not subject annotation , just return false + return false; + } + + if ( !hasRuntimeRetention() ){ + getLogger().log(Level.WARNING, "Annotation " + + getElement().getQualifiedName() + + " declared as " +getAnnotation()+" but has wrong retention policy." + + " Correct retention policy is " + + RetentionPolicy.RUNTIME.toString());// NOI18N + return false; + } + + return hasTarget(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.annotation.RuntimeRetentionAnalyzer#handleNoRetention() + */ + @Override + protected void handleNoRetention() { + getLogger().log(Level.WARNING, "Annotation " + + getElement().getQualifiedName() + + "declared as " +getAnnotation()+" but has no Retention");// NOI18N + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.annotation.TargetAnalyzer#handleNoTarget() + */ + @Override + protected void handleNoTarget() { + getLogger().log(Level.WARNING, "Annotation " + + getElement().getQualifiedName() + + "declared as " +getAnnotation()+" but has no Target");// NOI18N + } + + protected abstract Logger getLogger(); + + protected abstract String getAnnotation(); + + @Override + protected TypeElement getElement(){ + return (TypeElement)super.getElement(); + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/ScopeChecker.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/ScopeChecker.java new file mode 100644 index 000000000000..d625481323aa --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/ScopeChecker.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.lang.annotation.ElementType; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.AnnotationMirror; + +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.ScopeVerifier; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.TargetVerifier; + + +/** + * @author ads + * + */ +class ScopeChecker extends RuntimeAnnotationChecker { + + static String SCOPE = "jakarta.inject.Scope"; // NOI18N + + static String NORMAL_SCOPE = "jakarta.enterprise.context.NormalScope";// NOI18N + + static ScopeChecker get(){ + return new ScopeChecker(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.RuntimeAnnotationChecker#getLogger() + */ + @Override + protected Logger getLogger() { + return Logger.getLogger(ScopeChecker.class.getName()); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.RuntimeAnnotationChecker#getAnnotation() + */ + @Override + protected String getAnnotation() { + return SCOPE; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.annotation.TargetAnalyzer#getTargetVerifier() + */ + @Override + protected TargetVerifier getTargetVerifier() { + return ScopeVerifier.getInstance(); + } + + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.TargetAnalyzer#hasReqiredTarget(javax.lang.model.element.AnnotationMirror, java.util.Set) + */ + @Override + public boolean hasReqiredTarget( AnnotationMirror target, + Set set ) + { + boolean hasRequiredTarget = super.hasReqiredTarget(target, set); + if (!hasRequiredTarget) { + getLogger().log(Level.WARNING, + "Annotation "+getElement().getQualifiedName()+ + "declared as Scope but has wrong target values." + + " Correct target values are {METHOD, FIELD, TYPE}");// NOI18N + } + return hasRequiredTarget; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/SingleResultLookupStrategy.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/SingleResultLookupStrategy.java new file mode 100644 index 000000000000..4e15d41a5129 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/SingleResultLookupStrategy.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.concurrent.atomic.AtomicBoolean; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.impl.model.results.ResultImpl; + +public class SingleResultLookupStrategy implements ResultLookupStrategy { + + protected SingleResultLookupStrategy(){ + } + + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.ResultLookupStrategy#getResult(org.netbeans.modules.jakarta.web.beans.impl.model.WebBeansModelImplementation, org.netbeans.modules.jakarta.web.beans.api.model.Result) + */ + @Override + public DependencyInjectionResult getResult( WebBeansModelImplementation model , DependencyInjectionResult result, AtomicBoolean cancel ) { + /* + * Simple filtering related to production elements types. + * F.e. there could be injection point with String type. + * String is unproxyable type ( it is final ) so it cannot + * be used as injectable type. Only appropriate production element + * is valid injectable. But String will be found as result of previous + * procedure. So it should be removed. + */ + filterBeans( result , model, cancel ); + + result = filterEnabled(result , model, cancel); + + return result; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.ResultLookupStrategy#getType(org.netbeans.modules.jakarta.web.beans.impl.model.WebBeansModelImplementation, javax.lang.model.type.DeclaredType, javax.lang.model.element.VariableElement) + */ + @Override + public TypeMirror getType( WebBeansModelImplementation model, + DeclaredType parent, VariableElement element ) + { + return model.getHelper().getCompilationController().getTypes(). + asMemberOf(parent, element ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.ResultLookupStrategy#getType(org.netbeans.modules.jakarta.web.beans.impl.model.WebBeansModelImplementation, javax.lang.model.type.TypeMirror) + */ + @Override + public TypeMirror getType( WebBeansModelImplementation model, + TypeMirror typeMirror ) { + return typeMirror; + } + + protected void filterBeans( DependencyInjectionResult result, WebBeansModelImplementation model, AtomicBoolean cancel ) { + if ( result instanceof ResultImpl ){ + BeansFilter filter = BeansFilter.get(); + filter.filter(((ResultImpl)result).getTypeElements() ); + } + } + + protected DependencyInjectionResult filterEnabled( DependencyInjectionResult result, + WebBeansModelImplementation model, AtomicBoolean cancel) + { + if ( result instanceof ResultImpl ){ + EnableBeansFilter filter = new EnableBeansFilter((ResultImpl)result, + model , false ); + return filter.filter(cancel); + } + return result; + } +} \ No newline at end of file diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/StereotypeChecker.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/StereotypeChecker.java new file mode 100644 index 000000000000..d62eccadc3e0 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/StereotypeChecker.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.lang.annotation.ElementType; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationHelper; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.StereotypeVerifier; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.TargetVerifier; + + +/** + * @author ads + * + */ +public class StereotypeChecker extends RuntimeAnnotationChecker { + + static final String STEREOTYPE = "jakarta.enterprise.inject.Stereotype"; //NOI18N + + public StereotypeChecker(AnnotationHelper helper ){ + init(null, helper); + } + + public void init( TypeElement element) { + assert getElement() == null; + super.init(element, getHelper()); + } + + + public void clean(){ + init( null , getHelper() ); + } + + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analyzer.annotation.TargetAnalyzer#hasReqiredTarget(javax.lang.model.element.AnnotationMirror, java.util.Set) + */ + @Override + public boolean hasReqiredTarget( AnnotationMirror target, + Set set ) + { + boolean hasRequiredTarget = super.hasReqiredTarget(target, set); + if(!hasRequiredTarget){ + getLogger().log(Level.WARNING, + "Annotation "+getElement().getQualifiedName()+ + "declared as Qualifier but has wrong target values." + + " Correct target values are {METHOD, FIELD, TYPE} or" + + "{METHOD, FIELD} or TYPE or METHOD or FIELD");// NOI18N + } + return hasRequiredTarget; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.analizer.annotation.TargetAnalyzer#getTargetVerifier() + */ + @Override + protected TargetVerifier getTargetVerifier() { + return StereotypeVerifier.getInstance(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.RuntimeAnnotationChecker#getAnnotation() + */ + @Override + protected String getAnnotation() { + return STEREOTYPE; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.RuntimeAnnotationChecker#getLogger() + */ + @Override + protected Logger getLogger() { + return Logger.getLogger(StereotypeChecker.class.getName()); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/StereotypedObject.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/StereotypedObject.java new file mode 100644 index 000000000000..390a88941887 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/StereotypedObject.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.List; +import java.util.Map; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.PersistentObject; +import org.netbeans.modules.jakarta.web.beans.impl.model.AbstractObjectProvider.Refreshable; + + +/** + * Represents TypeElement annotated with some stereotype. + * + * @author ads + * + */ +class StereotypedObject extends PersistentObject implements Refreshable { + + public StereotypedObject( String stereotype , AnnotationModelHelper helper, + TypeElement typeElement ) + { + super(helper, typeElement); + myStereotype = stereotype; + boolean valid = refresh(typeElement); + assert valid; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractObjectProvider.Refreshable#refresh(javax.lang.model.element.TypeElement) + */ + @Override + public boolean refresh( TypeElement type ) { + List allAnnotationMirrors = + getHelper().getCompilationController().getElements(). + getAllAnnotationMirrors(type); + Map annotationsByType = + getHelper().getAnnotationsByType( allAnnotationMirrors ); + return annotationsByType.get( myStereotype) != null ; + } + + private String myStereotype; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/StereotypedObjectProvider.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/StereotypedObjectProvider.java new file mode 100644 index 000000000000..7d23252fe45a --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/StereotypedObjectProvider.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import javax.lang.model.element.TypeElement; + +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; + + +/** + * Provider for type elements which are annotated with some stereotype. + * + * @author ads + * + */ +class StereotypedObjectProvider extends AbstractObjectProvider +{ + + StereotypedObjectProvider( String stereotypeAnnotation , + AnnotationModelHelper helper ) + { + super( stereotypeAnnotation, helper); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.AbstractObjectProvider#createTypeElement(javax.lang.model.element.TypeElement) + */ + @Override + protected StereotypedObject createTypeElement( TypeElement element ) { + return new StereotypedObject( getAnnotation(), getHelper() , element ); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/TypeBindingFilter.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/TypeBindingFilter.java new file mode 100644 index 000000000000..4a6f2867fe5f --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/TypeBindingFilter.java @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ReferenceType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Types; + +import org.netbeans.modules.jakarta.web.beans.impl.model.AbstractAssignabilityChecker.AssignabilityType; + + + +/** + * @author ads + * + */ +class TypeBindingFilter extends Filter { + + static TypeBindingFilter get() { + // could be changed to cached ThreadLocal access + return new TypeBindingFilter(); + } + + void init( TypeMirror varType , Element injectionPoint, WebBeansModelImplementation modelImpl ) + { + mySimpleName = injectionPoint.getSimpleName().toString(); + myImpl = modelImpl; + myVarType = varType; + myInjectionPoint = injectionPoint; + + setIsGeneric(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.TypeFilter#filter(java.util.Set) + */ + @Override + void filter( Set set ) { + super.filter(set); + if ( set.size() == 0 ){ + return; + } + TypeKind kind = getType().getKind(); + if ( kind == TypeKind.DECLARED ){ + filterDeclaredTypes(set); + } + else if ( kind.isPrimitive() ){ + WebBeansModelProviderImpl.LOGGER.fine("Variable element " + + mySimpleName+ " " + + "couldn't have type as eligible for inection becuase its " + + "type is primitive. It is unproxyable bean types"); // NOI18N + set.clear(); + } + else if ( kind == TypeKind.ARRAY ){ + WebBeansModelProviderImpl.LOGGER.fine("Variable element " + + mySimpleName+ " " + + "couldn't have type as eligible for inection becuase its " + + "type has array type. It is unproxyable bean types");// NOI18N + set.clear(); + } + } + + /* + * type type for assignability check, + * sourceElement the element which the source of the type. + * The latter element could be either Type element or production element. + */ + boolean isAssignable( TypeMirror type , Element sourceElement ){ + if ( !isGeneric ) { + Collection restrictedTypes = RestrictedTypedFilter. + getRestrictedTypes(sourceElement, getImplementation()); + if ( restrictedTypes == null ){ + if ( getImplementation().getHelper(). + getCompilationController().getTypes().isAssignable( + type, getType())) + { + WebBeansModelProviderImpl.LOGGER.fine("Found type " + +type+ " for variable element " +mySimpleName + + " by typesafe resolution"); // NOI18N + return true; + } + } + else { + Types types = getImplementation().getHelper(). + getCompilationController().getTypes(); + for( TypeMirror restrictedType : restrictedTypes ){ + if ( types.isSameType( types.erasure( getType()), + types.erasure( restrictedType))) + { + WebBeansModelProviderImpl.LOGGER.fine("Found type " + +type+" for variable element " +mySimpleName + + " by typesafe resolution"); // NOI18N + return true; + } + } + } + } + if ( checkAssignability( type , sourceElement )){ + WebBeansModelProviderImpl.LOGGER.fine("Probably found " + + "castable parametrizied or raw type " + + type+" for variable element " +mySimpleName+ + " by typesafe resolution"); // NOI18N + return true; + } + return false; + } + + private void setIsGeneric(){ + Element typeElement = getImplementation().getHelper(). + getCompilationController().getTypes().asElement(getType()); + + isGeneric = (typeElement instanceof TypeElement) && + ((TypeElement)typeElement).getTypeParameters().size() != 0; + } + + private void filterDeclaredTypes( Set set ) + { + for ( Iterator iterator = set.iterator(); + iterator.hasNext(); ) + { + TypeElement type = iterator.next(); + if ( !isAssignable(type.asType() , type )){ + iterator.remove(); + } + } + } + + private boolean checkAssignability( TypeMirror type, Element originalElement ){ + if ( !(type instanceof ReferenceType )){ + return false; + } + Element injectionPoint = getInjectionPoint(); + AssignabilityType assignType = AssignabilityType.PLAIN; + if ( injectionPoint != null && AnnotationObjectProvider. + hasAnnotation(injectionPoint, + FieldInjectionPointLogic.DELEGATE_ANNOTATION, + getImplementation().getHelper())) + { + assignType = AssignabilityType.DECORATOR; + } + AbstractAssignabilityChecker checker = AbstractAssignabilityChecker.get( + assignType); + checker.init((DeclaredType)getType(), (ReferenceType)type, + originalElement, getImplementation()); + return checker.check(); + } + + + private TypeMirror getType(){ + return myVarType; + } + + private Element getInjectionPoint(){ + return myInjectionPoint; + } + + private WebBeansModelImplementation getImplementation(){ + return myImpl; + } + + private TypeMirror myVarType; + private WebBeansModelImplementation myImpl; + private String mySimpleName; + private boolean isGeneric; + private Element myInjectionPoint; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/TypeProductionFilter.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/TypeProductionFilter.java new file mode 100644 index 000000000000..bcd887b1aec5 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/TypeProductionFilter.java @@ -0,0 +1,346 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.PrimitiveType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Types; + + +/** + * @author ads + * + */ +class TypeProductionFilter extends Filter { + + private TypeProductionFilter( ){ + } + + static TypeProductionFilter get( ){ + // could be cached via ThreadLocal attribute + return new TypeProductionFilter(); + } + + void init( TypeMirror elementType , Element injectionPoint , + WebBeansModelImplementation model) + { + myImpl = model; + myType = elementType; + myOriginalElement = injectionPoint; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.Filter#filterElements(java.util.Set) + */ + @Override + void filter( Set productionElements ){ + if ( filterPrimitives(productionElements ) ){ + //fillSimpleResult(productionElements); + return; + } + + if ( filterArray(productionElements) ){ + //fillSimpleResult(productionElements); + return ; + } + + TypeBindingFilter filter = TypeBindingFilter.get(); + filter.init(getElementType(), getOriginalElement(), getImplementation()); + + // this cycle care only about declared types. + for ( Iterator iterator = productionElements.iterator() ; + iterator.hasNext() ; ) + { + Element productionElement = iterator.next(); + + TypeMirror mirror = null; + if (productionElement.getKind() == ElementKind.FIELD) { + mirror = productionElement.asType(); + } + else if (productionElement.getKind() == ElementKind.METHOD) + { + mirror = ((ExecutableType) productionElement.asType()).getReturnType(); + } + if ( !filter.isAssignable(mirror, productionElement )){ + iterator.remove(); + } + + /*List derived = getDerived( enclosingElement); + + for (DeclaredType declaredType : derived) { + TypeMirror mirror = null; + try { + if (productionElement.getKind() == ElementKind.FIELD) { + mirror = getImplementation().getHelper() + .getCompilationController().getTypes() + .asMemberOf(declaredType, productionElement); + } + else if (productionElement.getKind() == ElementKind.METHOD) + { + mirror = getImplementation().getHelper() + .getCompilationController().getTypes() + .asMemberOf(declaredType, productionElement); + mirror = ((ExecutableType) mirror).getReturnType(); + } + if ( filter.isAssignable(mirror, productionElement )){ + addResult( productionElement , declaredType); + } + } + catch (IllegalArgumentException e) { + /* + * call asMemberOf could be a problem for + * productionElment and derived. In this case just skip + * + continue; + } + }*/ + } + } + + /*private void addResult( Element productionElement, DeclaredType type ) + { + List list = myResult.get( productionElement ); + if ( list == null ){ + list = new ArrayList(2); + myResult.put( productionElement , list ); + } + list.add( type ); + } + + private void fillSimpleResult( Set productionElements ){ + for (Element element : productionElements) { + TypeElement enclosingElement = getImplementation().getHelper(). + getCompilationController().getElementUtilities(). + enclosingTypeElement(element); + DeclaredType type = (DeclaredType)enclosingElement.asType(); + myResult.put( element , Collections.singletonList(type) ); + } + }*/ + + /* + * From the spec : producer or disposer method is not inherited. + * producer field is not inherited. + * It means no need to look at the derived classes and inherited + * production there. If method is explicitly defined in the + * derived class it will be in the original production list + * as separate element. + private List getDerived( TypeElement element ) + { + if ( !isGeneric( element ) ){ + return Collections.singletonList( (DeclaredType)element.asType()); + } + + Set implementors = FieldInjectionPointLogic. + getImplementors(getImplementation(), element); + List result = new ArrayList( + implementors.size()); + for (TypeElement typeElement : implementors) { + result.add((DeclaredType)typeElement.asType()); + } + + return result; + + } + + private boolean isGeneric( TypeElement element ) { + //DeclaredType type = (DeclaredType)element.asType(); + return element.getTypeParameters().size()!=0; + }*/ + + private boolean filterArray( Set productionElements) + { + if ( getElementType().getKind() == TypeKind.ARRAY ){ + TypeMirror arrayComponentType = ((ArrayType)getElementType()).getComponentType(); + for (Iterator iterator = productionElements.iterator() ; + iterator.hasNext() ; ) + { + Element productionElement = iterator.next(); + boolean hasBeanType = hasBeanType(arrayComponentType, + productionElement); + if ( !hasBeanType ){ + iterator.remove(); + } + } + return true; + } + return false; + } + + private boolean hasBeanType( TypeMirror arrayComponentType, + Element productionElement ) + { + Collection restrictedTypes = RestrictedTypedFilter. + getRestrictedTypes(productionElement, getImplementation()); + if ( restrictedTypes == null ){ + TypeMirror productionType= null; + if ( productionElement.getKind() == ElementKind.FIELD){ + productionType = productionElement.asType(); + } + else if ( productionElement.getKind() == ElementKind.METHOD){ + productionType = ((ExecutableElement)productionElement). + getReturnType(); + } + return checkArrayBeanType(productionType, arrayComponentType); + } + Types types = getImplementation().getHelper(). + getCompilationController().getTypes(); + for( TypeMirror restrictedType : restrictedTypes ){ + if ( types.isSameType( restrictedType, getElementType())){ + return true; + } + } + return false; + } + + private boolean checkArrayBeanType(TypeMirror productionType, + TypeMirror arrayComponentType) + { + if ( productionType == null ){ + return false; + } + if ( productionType.getKind() != TypeKind.ARRAY ){ + return false; + } + return getImplementation().getHelper().getCompilationController(). + getTypes().isSameType( arrayComponentType, + ((ArrayType) productionType).getComponentType()); + } + + private boolean filterPrimitives( Set productionElements ) + { + PrimitiveType primitive = null; + TypeElement boxedType = null; + if ( getElementType().getKind().isPrimitive() ){ + primitive = getImplementation().getHelper().getCompilationController(). + getTypes().getPrimitiveType( getElementType().getKind()); + boxedType = getImplementation().getHelper().getCompilationController(). + getTypes().boxedClass( primitive); + } + else if ( getElementType().getKind() == TypeKind.DECLARED ){ + Element varElement = getImplementation().getHelper(). + getCompilationController().getTypes().asElement( getElementType() ); + if ( varElement instanceof TypeElement ){ + String typeName = ((TypeElement)varElement).getQualifiedName(). + toString(); + if ( WRAPPERS.contains( typeName )){ + primitive = getImplementation().getHelper(). + getCompilationController().getTypes().unboxedType( + varElement.asType()); + boxedType = (TypeElement)varElement; + } + + } + } + + if ( primitive!= null ){ + for( Iterator iterator = productionElements.iterator(); + iterator.hasNext(); ) + { + Element productionElement =iterator.next(); + Types types = getImplementation().getHelper(). + getCompilationController().getTypes(); + TypeMirror productionType = null; + if ( productionElement.getKind() == ElementKind.FIELD){ + productionType = productionElement.asType(); + } + else if ( productionElement.getKind() == ElementKind.METHOD){ + productionType = ((ExecutableElement)productionElement). + getReturnType(); + } + Collection restrictedTypes = + RestrictedTypedFilter.getRestrictedTypes(productionElement, + getImplementation()); + /* + * The required type is either primitive or its wrapper. + * It means that bean type should be either the same primitive + * or wrapper. But all wrappers are final so production cannot + * restrict some child type of wrapper to wrapper. + * It can restrict only wrapper to wrapper parent. + * In this case the types are not assignable. + */ + boolean isNotRestricted = true; + if ( restrictedTypes!= null ){ + isNotRestricted = false; + for (TypeMirror restrictedType : restrictedTypes ){ + if ( types.isSameType( restrictedType, primitive )|| + types.isSameType( restrictedType, boxedType.asType() ) ) + { + isNotRestricted = true; + break; + } + } + } + if ( !isNotRestricted ){ + iterator.remove(); + } + else if ( productionType!= null && + !types.isSameType( productionType, primitive ) && + !types.isSameType( productionType , boxedType.asType())) + { + iterator.remove(); + } + } + } + + return primitive!= null; + } + + + private WebBeansModelImplementation getImplementation(){ + return myImpl; + } + + private TypeMirror getElementType(){ + return myType; + } + + private Element getOriginalElement(){ + return myOriginalElement; + } + + private WebBeansModelImplementation myImpl; + private TypeMirror myType; + private Element myOriginalElement; + + + private static final Set WRAPPERS = new HashSet(); + + static { + WRAPPERS.add(Boolean.class.getCanonicalName()); + WRAPPERS.add(Byte.class.getCanonicalName()); + WRAPPERS.add(Character.class.getCanonicalName()); + WRAPPERS.add(Double.class.getCanonicalName()); + WRAPPERS.add(Float.class.getCanonicalName()); + WRAPPERS.add(Integer.class.getCanonicalName()); + WRAPPERS.add(Long.class.getCanonicalName()); + WRAPPERS.add(Short.class.getCanonicalName()); + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/WebBeansModelImplementation.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/WebBeansModelImplementation.java new file mode 100644 index 000000000000..462c5604cf2c --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/WebBeansModelImplementation.java @@ -0,0 +1,217 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.io.IOException; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelException; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.PersistentObjectManager; +import org.netbeans.modules.j2ee.metadata.model.spi.MetadataModelImplementation; +import org.netbeans.modules.jakarta.web.beans.api.model.AbstractModelImplementation; +import org.netbeans.modules.jakarta.web.beans.api.model.BeansModel; +import org.netbeans.modules.jakarta.web.beans.api.model.ModelUnit; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class WebBeansModelImplementation extends AbstractModelImplementation + implements MetadataModelImplementation +{ + + protected WebBeansModelImplementation( ModelUnit unit ){ + super( unit ); + myManagers = new HashMap>(); + myStereotypedManagers = new HashMap>(); + myHelper = AnnotationModelHelper.create( getModelUnit().getClassPathInfo() ); + } + + public static MetadataModelImplementation createMetaModel( + ModelUnit unit ) + { + return new WebBeansModelImplementation( unit ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.AbstractModelImplementation#getBeansModel() + */ + @Override + public BeansModel getBeansModel() { + return super.getBeansModel(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.j2ee.metadata.model.spi.MetadataModelImplementation#isReady() + */ + @Override + public boolean isReady() { + return !getHelper().isJavaScanInProgress(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.j2ee.metadata.model.spi.MetadataModelImplementation#runReadAction(org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction) + */ + @Override + public R runReadAction( final MetadataModelAction action ) + throws MetadataModelException, IOException + { + return getHelper().runJavaSourceTask(new Callable() { + @Override + public R call() throws Exception { + return action.run(getModel()); + } + }); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.j2ee.metadata.model.spi.MetadataModelImplementation#runReadActionWhenReady(org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction) + */ + @Override + public Future runReadActionWhenReady( + final MetadataModelAction action ) + throws MetadataModelException, IOException + { + return getHelper().runJavaSourceTaskWhenScanFinished(new Callable() { + @Override + public R call() throws Exception { + return action.run(getModel()); + } + }); + } + + protected AnnotationModelHelper getHelper() { + return myHelper; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.AbstractModelImplementation#getModel() + */ + @Override + protected WebBeansModel getModel() { + return super.getModel(); + } + + Map> getManagers(){ + return myManagers; + } + + PersistentObjectManager getManager( String annotationFQN ){ + PersistentObjectManager result = getManagers().get( + annotationFQN); + if ( result == null ) { + result = getHelper().createPersistentObjectManager( + new AnnotationObjectProvider( getHelper(), annotationFQN)); + getManagers().put( annotationFQN , result); + } + return result; + } + + PersistentObjectManager getNamedManager(){ + return getManager( FieldInjectionPointLogic.NAMED_QUALIFIER_ANNOTATION ); + } + + PersistentObjectManager getNamedStereotypesManager(){ + if ( myStereotypesManager == null ){ + myStereotypesManager = getHelper().createPersistentObjectManager( + new NamedStereotypeObjectProvider( getHelper())); + } + return myStereotypesManager; + } + + PersistentObjectManager getStereotypedManager( + String stereotype ) + { + PersistentObjectManager result = + getStereotypedManagers().get(stereotype); + if ( result == null ) { + result = getHelper().createPersistentObjectManager( + new StereotypedObjectProvider( stereotype, getHelper())); + getStereotypedManagers().put( stereotype , result); + } + return result; + } + + Map> getStereotypedManagers(){ + return myStereotypedManagers; + } + + PersistentObjectManager getDecoratorsManager(){ + if ( myDecoratorsManager == null ){ + myDecoratorsManager = getHelper().createPersistentObjectManager( + new DecoratorObjectProvider( getHelper())); + } + return myDecoratorsManager; + } + + PersistentObjectManager getInterceptorsManager(){ + if ( myInterceptorsManager == null ){ + myInterceptorsManager = getHelper().createPersistentObjectManager( + new InterceptorObjectProvider( getHelper())); + } + return myInterceptorsManager; + } + + Set adjustStereotypesManagers(){ + Set stereotypes = getStereotypedManagers().keySet(); + Collection namedStereotypes = getNamedStereotypesManager(). + getObjects(); + Set existingStereotypes = new HashSet(namedStereotypes.size()); + for (NamedStereotype namedStereotype : namedStereotypes) { + if( namedStereotype!=null && namedStereotype.getTypeElement()!=null) { + String name = namedStereotype.getTypeElement().getQualifiedName(). + toString(); + if ( !stereotypes.contains( name)){ + getStereotypedManager(name); + } + existingStereotypes.add( name ); + } + } + if ( existingStereotypes.size() == getStereotypedManagers().keySet().size()){ + return existingStereotypes; + } + for (Iterator iterator = getStereotypedManagers().keySet().iterator(); + iterator.hasNext(); ) + { + String stereotype = iterator.next(); + if ( !existingStereotypes.contains( stereotype)){ + iterator.remove(); + } + } + return existingStereotypes; + } + + private Map> myManagers; + private PersistentObjectManager myStereotypesManager; + private PersistentObjectManager myDecoratorsManager; + private PersistentObjectManager myInterceptorsManager; + private Map> myStereotypedManagers; + private AnnotationModelHelper myHelper; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/WebBeansModelProviderImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/WebBeansModelProviderImpl.java new file mode 100644 index 000000000000..8ca193b901d1 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/WebBeansModelProviderImpl.java @@ -0,0 +1,642 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.api.java.source.ClassIndexListener; +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.RootsEvent; +import org.netbeans.api.java.source.TypesEvent; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationHelper; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.PersistentObjectManager; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.parser.AnnotationParser; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.parser.ParseResult; +import org.netbeans.modules.jakarta.web.beans.CdiUtil; +import org.netbeans.modules.jakarta.web.beans.api.model.BeanArchiveType; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class WebBeansModelProviderImpl extends DecoratorInterceptorLogic { + + protected WebBeansModelProviderImpl(WebBeansModelImplementation model){ + super( model ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider#getCompilationController() + */ + @Override + public CompilationController getCompilationController(){ + return getModel().getHelper().getCompilationController(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider#resolveType(java.lang.String) + */ + @Override + public TypeMirror resolveType( String fqn ) { + return getModel().getHelper().resolveType( fqn ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider#lookupInjectables(javax.lang.model.element.VariableElement, javax.lang.model.type.DeclaredType) + */ + @Override + public DependencyInjectionResult lookupInjectables(VariableElement element, DeclaredType parentType, AtomicBoolean cancel) { + TypeMirror type = getParameterType(element, null, INSTANCE_INTERFACE); + if ( type != null ){ + return lookupInjectables(element, parentType , + ResultLookupStrategy.MULTI_LOOKUP_STRATEGY, cancel); + } + else { + return lookupInjectables(element, parentType , + ResultLookupStrategy.SINGLE_LOOKUP_STRATEGY, cancel ); + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider#isInjectionPoint(javax.lang.model.element.VariableElement) + */ + @Override + public boolean isInjectionPoint( VariableElement element ) + throws org.netbeans.modules.jakarta.web.beans.api.model.InjectionPointDefinitionError + { + Element parent = element.getEnclosingElement(); + + if ( parent instanceof TypeElement){ + List annotations = + getModel().getHelper().getCompilationController().getElements(). + getAllAnnotationMirrors(element); + return getModel().getHelper().hasAnnotation(annotations, INJECT_ANNOTATION); + } + else if ( parent instanceof ExecutableElement ){ + return isMethodParameterInjection(element,(ExecutableElement)parent); + } + return false; + } + + @Override + public List getQualifiers(Element element, boolean all ) { + final boolean event = getParameterType(element, null, EVENT_INTERFACE) != null; + + final LinkedHashSet result = new LinkedHashSet(); + final AnnotationObjectProvider.AnnotationHandleStrategy strategy = new + AnnotationObjectProvider.AnnotationHandleStrategy() { + + @Override + public void handleAnnotation( AnnotationMirror annotationMirror, + TypeElement annotation ) + { + result.add( annotationMirror ); + } + }; + AnnotationObjectProvider.findQualifiers(element, getModel().getHelper(), + event, strategy); + boolean isType = element instanceof TypeElement; + boolean isMethod = element instanceof ExecutableElement; + if ( all && ( isType || isMethod ) ){ + AnnotationObjectProvider.SpecializeVisitor visitor = new + AnnotationObjectProvider.SpecializeVisitor() { + + @Override + public boolean visit( ExecutableElement overridenElement ) { + collectQualifiers(overridenElement); + return false; + } + + @Override + public boolean visit( TypeElement superElement ) { + collectQualifiers(superElement); + return false; + } + + private void collectQualifiers( Element element ){ + AnnotationObjectProvider.findQualifiers(element, + getModel().getHelper(), event, strategy); + } + }; + if ( isType ){ + AnnotationObjectProvider.visitSpecializes((TypeElement)element, + getModel().getHelper(), visitor); + } + else if ( isMethod ){ + MemberCheckerFilter.visitSpecializes((ExecutableElement)element, + getModel().getHelper(), visitor); + } + } + return new ArrayList( result ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider#hasImplicitDefaultQualifier(javax.lang.model.element.Element) + */ + @Override + public boolean hasImplicitDefaultQualifier( Element element ) { + boolean event = getParameterType(element, null, EVENT_INTERFACE) != null; + Set qualifiers = AnnotationObjectProvider.getQualifiers(element, + getModel().getHelper(), event); + if ( qualifiers.size() == 1 ){ + String qualifier = qualifiers.iterator().next(); + return qualifier.equals( NAMED_QUALIFIER_ANNOTATION ); + } + return qualifiers.size() == 0; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider#getName(javax.lang.model.element.Element) + */ + @Override + public String getName( Element element) + { + String name = inspectSpecializes( element ); + if ( name != null ){ + return name; + } + List allStereotypes = getAllStereotypes(element, + getModel().getHelper().getHelper()); + for (AnnotationMirror annotationMirror : allStereotypes) { + DeclaredType annotationType = annotationMirror.getAnnotationType(); + TypeElement annotation = (TypeElement)annotationType.asElement(); + if ( AnnotationObjectProvider.hasAnnotation(annotation, + NAMED_QUALIFIER_ANNOTATION, getModel().getHelper() ) ) + { + return getNamedName(element , null); + } + } + return null; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider#getNamedElements() + */ + @Override + public List getNamedElements(AtomicBoolean cancel) { + boolean dirty = isDirty.getAndSet( false ); + + if ( !isIndexListenerAdded ){ + addIndexListener( ); + } + + if ( !dirty ) { + List result = getCachedNamedElements( ); + if ( !isDirty.get() ) { + return result; + } + } + + List result = new LinkedList(); + Collection objects = getModel().getNamedManager().getObjects(); + for (BindingQualifier named : objects) { + TypeElement element = named.getTypeElement(); + // filter stereotypes + if ( element!= null && element.getKind() != ElementKind.ANNOTATION_TYPE) { + result.add( element ); + } + } + List members = AbstractObjectProvider.getNamedMembers( + getModel().getHelper() ); + for (Element element : members) { + if ( element== null || element.getKind()!= ElementKind.METHOD ){ + continue; + } + Set childSpecializes = getChildSpecializes( element, getModel(), cancel); + result.addAll( childSpecializes ); + } + result.addAll( members ); + + Set stereotypeNames = getModel().adjustStereotypesManagers(); + for (String stereotype : stereotypeNames) { + PersistentObjectManager manager = + getModel().getStereotypedManager(stereotype); + Collection beans = manager.getObjects(); + for (StereotypedObject bean : beans) { + TypeElement element = bean.getTypeElement(); + // filter stereotypes + if ( element!= null && element.getKind() != ElementKind.ANNOTATION_TYPE) { + result.add( element ); + } + } + List stereotypedMembers = StereotypedObjectProvider. + getAnnotatedMembers( stereotype, getModel().getHelper()); + result.addAll( stereotypedMembers ); + } + PackagingFilter filter = new PackagingFilter(getModel()); + filter.filter(result, cancel); + + setCachedResult( result ); + return result; + } + + @Override + public BeanArchiveType getBeanArchiveType() { + return getModel().getBeansModel().getBeanArchiveType(); + } + + @Override + public boolean isCdi11OrLater() { + return getModel().getBeansModel().isCdi11OrLater(); + } + + public static List getAllStereotypes( Element element , + AnnotationHelper helper ) + { + Set result = new HashSet(); + StereotypeChecker checker = new StereotypeChecker( helper); + doGetStereotypes(element, result, checker,helper); + return new ArrayList( result ); + } + + public static boolean isStereotype( TypeElement annotationElement, + StereotypeChecker checker ) + { + checker.init(annotationElement); + boolean result = checker.check(); + checker.clean(); + return result; + } + + protected DependencyInjectionResult lookupInjectables( VariableElement element, + DeclaredType parentType , ResultLookupStrategy strategy, AtomicBoolean cancel) + { + /* + * Element could be injection point. One need first if all to check this. + */ + Element parent = element.getEnclosingElement(); + + if(cancel.get()) { + return null; + } + + if ( parent instanceof TypeElement){ + return findVariableInjectable(element, parentType , strategy, cancel); + } + else if ( parent instanceof ExecutableElement ){ + // Probably injected field in method. One need to check method. + /* + * There are two cases where parameter is injected : + * 1) Method has some annotation which require from + * parameters to be injection points. + * 2) Method is disposer method. In this case injectable + * is producer corresponding method. + */ + return findParameterInjectable(element, parentType, strategy, cancel); + } + + return null; + } + + private boolean isMethodParameterInjection( VariableElement element, + ExecutableElement parent ) + throws org.netbeans.modules.jakarta.web.beans.api.model.InjectionPointDefinitionError + { + List annotations = + getModel().getHelper().getCompilationController().getElements(). + getAllAnnotationMirrors(parent); + if (isDisposeParameter( element, parent, annotations)){ + return true; + } + /* + * Parameter with @Observes annotation is not plain injection point. + */ + boolean hasObserves = AnnotationObjectProvider.hasAnnotation(element, + OBSERVES_ANNOTATION, getModel().getHelper()); + if ( !hasObserves && isObservesParameter(element, parent, annotations)){ + return true; + } + return getModel().getHelper().hasAnnotation(annotations, INJECT_ANNOTATION)|| + getModel().getHelper().hasAnnotation(annotations, PRODUCER_ANNOTATION); + } + + private void setCachedResult( List list) { + myNamedElement = new ArrayList>( list.size()); + for( Element element : list ){ + myNamedElement.add( ElementHandle.create( element )); + } + } + + private List getCachedNamedElements() { + List result = new ArrayList( myNamedElement.size()); + for ( ElementHandle handle : myNamedElement ){ + Element element = handle.resolve(getModel().getHelper(). + getCompilationController()); + if ( element != null ){ + result.add( element ); + } + } + return result; + } + + private void addIndexListener( ) { + isIndexListenerAdded = true; + final AnnotationModelHelper helper = getModel().getHelper(); + helper.getClasspathInfo().getClassIndex().addClassIndexListener( + new ClassIndexListener(){ + + @Override + public void typesAdded(final TypesEvent event) { + setDirty(); + } + + @Override + public void typesRemoved(final TypesEvent event) { + setDirty(); + } + + @Override + public void typesChanged(final TypesEvent event) { + setDirty(); + } + + @Override + public void rootsAdded(RootsEvent event) { + setDirty(); + } + + @Override + public void rootsRemoved(RootsEvent event) { + setDirty(); + } + + private void setDirty(){ + isDirty.set( true ); + + } + }); + } + + private String inspectSpecializes( Element element){ + if (element instanceof TypeElement) { + String name = doGetName(element, element); + if ( name != null ){ + return name; + } + TypeElement superElement = AnnotationObjectProvider.checkSuper( + (TypeElement)element, NAMED_QUALIFIER_ANNOTATION, + getModel().getHelper()); + if ( superElement != null ){ + return doGetName(element, superElement); + } + } + else if ( element instanceof ExecutableElement ){ + String name = doGetName(element, element); + if ( name == null ){ + Element specialized = MemberCheckerFilter.getSpecialized( + (ExecutableElement)element, getModel(), + NAMED_QUALIFIER_ANNOTATION); + if ( specialized!= null ){ + return doGetName(element , specialized); + } + } + else { + return name; + } + } + else { + return doGetName(element, element); + } + return null; + } + + private String doGetName( Element original , Element element ){ + List annotations = getModel().getHelper(). + getCompilationController().getElements().getAllAnnotationMirrors( + element); + for (AnnotationMirror annotationMirror : annotations) { + DeclaredType type = annotationMirror.getAnnotationType(); + TypeElement annotationElement = (TypeElement)type.asElement(); + if ( NAMED_QUALIFIER_ANNOTATION.contentEquals( + annotationElement.getQualifiedName())) + { + return getNamedName( original , annotationMirror ); + } + } + return null; + } + + private static void doGetStereotypes( Element element , + Set result ,final StereotypeChecker checker , + AnnotationHelper helper ) + { + TransitiveAnnotationHandler handler = new TransitiveAnnotationHandler(){ + + @Override + public boolean proceed( Element annotatedElement, + TypeElement element , boolean isTargetAnnotation) + { + return isTargetAnnotation; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.DecoratorInterceptorLogic.TransitiveAnnotationHandler#isTargetAnotation(javax.lang.model.element.TypeElement) + */ + @Override + public boolean isTargetAnotation( TypeElement element ) { + return isStereotype( element, checker ); + } + + }; + transitiveVisitAnnotatedElements(element, result, helper, handler); + } + + private String getNamedName( Element element, AnnotationMirror namedAnnotation ) + { + if (namedAnnotation != null) { + AnnotationParser parser = AnnotationParser.create(getModel().getHelper()); + parser.expectString(RuntimeAnnotationChecker.VALUE, null); + ParseResult result = parser.parse(namedAnnotation); + String name = result.get(RuntimeAnnotationChecker.VALUE, String.class); + if ( name != null ){ + return name; + } + } + if ( element instanceof TypeElement ){ + String name = element.getSimpleName().toString(); + if ( name.length() >0 ){ + // XXX we may use Introspector.decapitalize + String withoutPrefix = name.substring(1); + // #249438 + if (!withoutPrefix.isEmpty() && Character.isUpperCase(withoutPrefix.charAt(0))) { + return name; + } else { + return Character.toLowerCase(name.charAt(0)) + withoutPrefix; + } + } + else { + return name; + } + } + if ( element instanceof VariableElement ){ + return element.getSimpleName().toString(); + } + if ( element instanceof ExecutableElement ){ + String name = element.getSimpleName().toString(); + if ( name.startsWith("get") && name.length() > 3 ){ // NOI18N + return getPropertyName(name, 3); + } + else if ( name.startsWith("is") && name.length() >2 ){ // NOI18N + return getPropertyName(name, 2); + } + return name; + } + return null; + } + + private String getPropertyName(String methodName, int prefixLength) { + String propertyName = methodName.substring(prefixLength); + String propertyNameWithoutFL = propertyName.substring(1); + + if (propertyNameWithoutFL.length() > 0) { + if (propertyNameWithoutFL.equals(propertyNameWithoutFL.toUpperCase())) { + //property is in uppercase + return propertyName; + } + } + return Character.toLowerCase(propertyName.charAt(0)) + propertyNameWithoutFL; + } + + /* + * Observer method could have only one parameter. + * Other parameters are error for observer method. + * They are not injection points. + */ + private boolean isObservesParameter( VariableElement element, + ExecutableElement method , List annotations ) + throws org.netbeans.modules.jakarta.web.beans.api.model.InjectionPointDefinitionError + { + List parameters = method.getParameters(); + boolean observesFound = false; + for (VariableElement variableElement : parameters) { + if ( AnnotationObjectProvider.hasAnnotation(variableElement, + OBSERVES_ANNOTATION, getModel().getHelper())) + { + if ( observesFound ){ + throw new org.netbeans.modules.jakarta.web.beans.api.model. + InjectionPointDefinitionError(method, + NbBundle.getMessage(WebBeansModelImplementation.class, + "ERR_MultipleObserves" , method.getSimpleName())); + } + observesFound = true; + } + } + if ( !observesFound ){ + return false; + } + + String badAnnotation = checkInjectProducers(annotations); + if ( badAnnotation != null ){ + throw new org.netbeans.modules.jakarta.web.beans.api.model. + InjectionPointDefinitionError( method, + NbBundle.getMessage(WebBeansModelImplementation.class, + "ERR_ObserverHasInjectOrProduces" , method.getSimpleName(), + badAnnotation )); + } + return observesFound; + } + + /* + * All parameters of disposer method are injection points. + */ + private boolean isDisposeParameter( VariableElement element, + ExecutableElement method , List annotations) + throws org.netbeans.modules.jakarta.web.beans.api.model.InjectionPointDefinitionError + { + List parameters = method.getParameters(); + boolean disposeFound = false; + boolean observesFound = false; + for (VariableElement variableElement : parameters) { + if ( AnnotationObjectProvider.hasAnnotation(variableElement, + DISPOSES_ANNOTATION, getModel().getHelper())) + { + if ( disposeFound ){ + throw new org.netbeans.modules.jakarta.web.beans.api.model. + InjectionPointDefinitionError(method, + NbBundle.getMessage(WebBeansModelImplementation.class, + "ERR_MultipleDisposes" , method.getSimpleName())); + } + disposeFound = true; + } + if ( AnnotationObjectProvider.hasAnnotation(variableElement, + OBSERVES_ANNOTATION, getModel().getHelper())) + { + observesFound = true; + } + } + if ( !disposeFound ){ + return false; + } + if ( observesFound ){ + throw new org.netbeans.modules.jakarta.web.beans.api.model. + InjectionPointDefinitionError(method, + NbBundle.getMessage(WebBeansModelImplementation.class, + "ERR_DisposesHasObserves" , method.getSimpleName())); + } + String badAnnotation = checkInjectProducers(annotations); + if ( badAnnotation != null ){ + throw new org.netbeans.modules.jakarta.web.beans.api.model. + InjectionPointDefinitionError( method, + NbBundle.getMessage(WebBeansModelImplementation.class, + "ERR_DisposesHasInjectOrProduces" , method.getSimpleName(), + badAnnotation )); + } + return disposeFound; + } + + private String checkInjectProducers(List annotations) + { + if (getModel().getHelper().hasAnnotation(annotations, + INJECT_ANNOTATION)) + { + return INJECT_ANNOTATION; + } + if ( getModel().getHelper().hasAnnotation(annotations, + PRODUCER_ANNOTATION)) + { + return PRODUCER_ANNOTATION; + } + return null; + } + + private AtomicBoolean isDirty = new AtomicBoolean(true); + private volatile boolean isIndexListenerAdded; + private List> myNamedElement; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/WebBeansProviderFactoryImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/WebBeansProviderFactoryImpl.java new file mode 100644 index 000000000000..1894df07db99 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/WebBeansProviderFactoryImpl.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model; + +import org.netbeans.modules.jakarta.web.beans.api.model.AbstractModelImplementation; +import org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProvider; +import org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProviderFactory; + + +/** + * @author ads + * + */ +@org.openide.util.lookup.ServiceProvider(service=WebBeansModelProviderFactory.class) +public class WebBeansProviderFactoryImpl implements + WebBeansModelProviderFactory +{ + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.model.spi.WebBeansModelProviderFactory#createWebBeansModelProvider(org.netbeans.modules.jakarta.web.beans.api.model.AbstractModelImplementation) + */ + @Override + public WebBeansModelProvider createWebBeansModelProvider( + AbstractModelImplementation model ) + { + if ( model instanceof WebBeansModelImplementation ){ + return new WebBeansModelProviderImpl( + (WebBeansModelImplementation)model ); + } + return null; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/BaseResult.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/BaseResult.java new file mode 100644 index 000000000000..a9df6029535b --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/BaseResult.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model.results; + +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; + + + +/** + * @author ads + * + */ +abstract class BaseResult implements DependencyInjectionResult { + + BaseResult( VariableElement element , TypeMirror type ){ + myElement = element; + myType = type; + } + + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.Result#getVariable() + */ + @Override + public VariableElement getVariable() { + return myElement; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.Result#getVariableType() + */ + @Override + public TypeMirror getVariableType() { + return myType; + } + + private final VariableElement myElement; + private final TypeMirror myType; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/DefinitionErrorResult.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/DefinitionErrorResult.java new file mode 100644 index 000000000000..02da4a93ce68 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/DefinitionErrorResult.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model.results; + +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; + + +/** + * @author ads + * + */ +public class DefinitionErrorResult extends BaseResult implements DependencyInjectionResult.Error { + + public DefinitionErrorResult( VariableElement var, TypeMirror type, + String error ) + { + super(var, type); + myMessage =error; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.Result.Error#getMessage() + */ + @Override + public String getMessage(){ + return myMessage; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.Result#getKind() + */ + @Override + public ResultKind getKind() { + return ResultKind.DEFINITION_ERROR; + } + + private final String myMessage; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/ErrorImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/ErrorImpl.java new file mode 100644 index 000000000000..b5eff0d39bf5 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/ErrorImpl.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model.results; + +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult.Error; + + +/** + * @author ads + * + */ +public class ErrorImpl extends BaseResult implements Error { + + public ErrorImpl( VariableElement var, TypeMirror type, + String error ) + { + super(var, type); + myMessage =error; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.Result.Error#getMessage() + */ + @Override + public String getMessage(){ + return myMessage; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.Result#getKind() + */ + @Override + public ResultKind getKind() { + return ResultKind.RESOLUTION_ERROR; + } + + private String myMessage; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/InjectableResultImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/InjectableResultImpl.java new file mode 100644 index 000000000000..a25514a7bca1 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/InjectableResultImpl.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model.results; + +import java.util.Set; + +import javax.lang.model.element.Element; + +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult.ApplicableResult; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult.InjectableResult; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult.ResolutionResult; + + +/** + * @author ads + * + */ +public class InjectableResultImpl extends ResultImpl implements InjectableResult, + ResolutionResult, ApplicableResult +{ + + public InjectableResultImpl( ResultImpl origin,Element injectable, + Set enabledBeans) + { + super(origin.getVariable(), origin.getVariableType(), + origin.getTypeElements(), origin.getProductions(), + origin.getHelper()); + myInjectable = injectable; + myEnabled = enabledBeans; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.Result.InjectableResult#getElement() + */ + @Override + public Element getElement() { + return myInjectable; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.Result.ApplicableResult#isDisabled(javax.lang.model.element.Element) + */ + @Override + public boolean isDisabled( Element element ) { + return !myEnabled.contains( element ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.results.ResultImpl#getKind() + */ + @Override + public ResultKind getKind() { + return ResultKind.INJECTABLE_RESOLVED; + } + + private final Element myInjectable; + private final Set myEnabled; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/InjectablesResultImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/InjectablesResultImpl.java new file mode 100644 index 000000000000..c02b92c1bd25 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/InjectablesResultImpl.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model.results; + +import java.util.Collections; +import java.util.Set; + +import javax.lang.model.element.Element; + +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult.ApplicableResult; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult.ResolutionResult; + + +/** + * @author ads + * + */ +public class InjectablesResultImpl extends ResultImpl implements + ResolutionResult, ApplicableResult +{ + + public InjectablesResultImpl( ResultImpl origin, Set enabledBeans) + { + super(origin.getVariable(), origin.getVariableType(), + origin.getTypeElements(), origin.getProductions(), + origin.getHelper()); + myEnabled = enabledBeans; + } + + public InjectablesResultImpl( ResultImpl origin ) { + super(origin.getVariable(), origin.getVariableType(), + origin.getTypeElements(), origin.getProductions(), + origin.getHelper()); + myEnabled =Collections.emptySet(); + } + + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.Result.ApplicableResult#isDisabled(javax.lang.model.element.Element) + */ + @Override + public boolean isDisabled( Element element ) { + return !myEnabled.contains( element ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.results.ResultImpl#getKind() + */ + @Override + public ResultKind getKind() { + return ResultKind.INJECTABLES_RESOLVED; + } + + private final Set myEnabled; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/InterceptorsResultImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/InterceptorsResultImpl.java new file mode 100644 index 000000000000..bee538a44050 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/InterceptorsResultImpl.java @@ -0,0 +1,210 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model.results; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.parser.AnnotationParser; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.parser.ArrayValueHandler; +import org.netbeans.modules.jakarta.web.beans.api.model.InterceptorsResult; +import org.netbeans.modules.jakarta.web.beans.impl.model.StereotypeChecker; +import org.netbeans.modules.jakarta.web.beans.impl.model.WebBeansModelProviderImpl; + + +/** + * @author ads + * + */ +public class InterceptorsResultImpl implements InterceptorsResult { + + static final String INTERCEPTORS = "jakarta.interceptor.Interceptors"; // NOI18N + + public InterceptorsResultImpl( Element element , + List enabledInterceptors, + Set disabledIntercaptors, + AnnotationModelHelper helper ) + { + mySubjectElement = element; + myHelper = helper; + myEnabledInterceptors = enabledInterceptors; + myDisabledInterceptors = disabledIntercaptors; + initDeclaredInterceptors(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.Result#getAllStereotypes(javax.lang.model.element.Element) + */ + @Override + public List getAllStereotypes( Element element ) { + return WebBeansModelProviderImpl.getAllStereotypes(element, + getHelper().getHelper()); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.Result#getStereotypes(javax.lang.model.element.Element) + */ + @Override + public List getStereotypes( Element element ) { + return getStereotypes(element, getHelper() ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.BeansResult#isDisabled(javax.lang.model.element.Element) + */ + @Override + public boolean isDisabled( Element element ) { + return myDisabledInterceptors.contains(element); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.InterceptorsResult#getElement() + */ + @Override + public Element getElement() { + return mySubjectElement; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.InterceptorsResult#getResolvedInterceptors() + */ + @Override + public List getResolvedInterceptors() { + int enabledSize = myEnabledInterceptors.size(); + int disabledSize = myDisabledInterceptors.size(); + ArrayList result = new ArrayList( enabledSize + + disabledSize ); + result.addAll( myEnabledInterceptors ); + result.addAll( myDisabledInterceptors ); + return result; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.InterceptorsResult#getDeclaredInterceptors() + */ + @Override + public List getDeclaredInterceptors() { + return myDeclaredInterceptors; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.InterceptorsResult#getAllInterceptors() + */ + @Override + public List getAllInterceptors() { + int enabledSize = myEnabledInterceptors.size(); + int disabledSize = myDisabledInterceptors.size(); + int declaredSize = myDeclaredInterceptors.size(); + ArrayList result = new ArrayList( enabledSize + + disabledSize +declaredSize); + result.addAll( myEnabledInterceptors ); + result.addAll( myDeclaredInterceptors ); + result.addAll( myDisabledInterceptors ); + return result; + } + + + private void initDeclaredInterceptors() { + final LinkedHashSet result = new LinkedHashSet(); + AnnotationParser parser = AnnotationParser.create( getHelper()); + parser.expectClassArray("value", new ArrayValueHandler() { + + @Override + public Object handleArray( List arrayMembers ) { + for (AnnotationValue arrayMember : arrayMembers) { + TypeMirror typeMirror = (TypeMirror) arrayMember.getValue(); + Element element = getController().getTypes(). + asElement( typeMirror ); + if ( element instanceof TypeElement ){ + result.add( (TypeElement)element ); + } + } + return null; + } + }, null); + Element subjectElement = getElement(); + if ( subjectElement instanceof ExecutableElement ){ + TypeElement enclosingType = getController().getElementUtilities(). + enclosingTypeElement( subjectElement); + fillDeclaredAnnotations(parser, enclosingType); + } + fillDeclaredAnnotations(parser, subjectElement); + myDeclaredInterceptors = new ArrayList( result ); + } + + private void fillDeclaredAnnotations( AnnotationParser parser, + Element subjectElement ) + { + List annotationMirrors = + getController().getElements().getAllAnnotationMirrors( subjectElement ); + AnnotationMirror annotationMirror = getHelper().getAnnotationsByType( + annotationMirrors).get(INTERCEPTORS); + if ( annotationMirror != null ){ + parser.parse(annotationMirror); + } + } + + static List getStereotypes( Element element , + AnnotationModelHelper helper) + { + List result = new LinkedList(); + List annotationMirrors = + helper.getCompilationController().getElements(). + getAllAnnotationMirrors( element ); + StereotypeChecker checker = new StereotypeChecker( helper.getHelper()); + for (AnnotationMirror annotationMirror : annotationMirrors) { + TypeElement annotationElement = (TypeElement)annotationMirror. + getAnnotationType().asElement(); + if ( annotationElement!= null && + WebBeansModelProviderImpl.isStereotype( annotationElement, + checker ) ) + { + result.add( annotationMirror ); + } + } + return result; + } + + private AnnotationModelHelper getHelper(){ + return myHelper; + } + + private CompilationController getController(){ + return getHelper().getCompilationController(); + } + + private Element mySubjectElement; + private List myEnabledInterceptors; + private Collection myDisabledInterceptors; + private List myDeclaredInterceptors; + private AnnotationModelHelper myHelper; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/ResolutionErrorImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/ResolutionErrorImpl.java new file mode 100644 index 000000000000..d6408f48e9e3 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/ResolutionErrorImpl.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model.results; + +import java.util.Set; + +import javax.lang.model.element.Element; + +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult.ApplicableResult; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult.Error; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult.ResolutionResult; + + +/** + * @author ads + * + */ +public class ResolutionErrorImpl extends InjectablesResultImpl implements Error, + ResolutionResult, ApplicableResult +{ + + public ResolutionErrorImpl( ResultImpl origin, String message , + Set enabledBeans) + { + super( origin , enabledBeans ); + myMessage = message; + } + + public ResolutionErrorImpl( ResultImpl origin, String message ) { + super( origin ); + myMessage = message; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.Result.Error#getMessage() + */ + @Override + public String getMessage() { + return myMessage; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.results.ResultImpl#getKind() + */ + @Override + public ResultKind getKind() { + return ResultKind.RESOLUTION_ERROR; + } + + private final String myMessage; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/ResultImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/ResultImpl.java new file mode 100644 index 000000000000..257b550b1d5f --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/impl/model/results/ResultImpl.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.impl.model.results; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.impl.model.WebBeansModelProviderImpl; + + +/** + * @author ads + * + */ +public class ResultImpl extends BaseResult implements DependencyInjectionResult.ResolutionResult { + + private static final String ALTERNATIVE = + "jakarta.enterprise.inject.Alternative"; // NOI18N + + public ResultImpl( VariableElement var, TypeMirror elementType , + Set declaredTypes, + Set productionElements, + AnnotationModelHelper helper ) + { + super( var, elementType ); + myDeclaredTypes = declaredTypes; + myProductions = productionElements; + myHelper = helper; + } + + public ResultImpl( VariableElement var, TypeMirror elementType , + TypeElement declaredType, AnnotationModelHelper helper ) + { + super( var, elementType ); + myDeclaredTypes =Collections.singleton( declaredType ); + myProductions = Collections.emptySet(); + myHelper = helper; + } + + public ResultImpl( VariableElement var, TypeMirror elementType , + AnnotationModelHelper helper ) + { + super( var, elementType ); + myDeclaredTypes =Collections.emptySet(); + myProductions = Collections.emptySet(); + myHelper = helper; + } + + public Set getTypeElements() { + return myDeclaredTypes; + } + + public Set getProductions() { + return myProductions; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.Result#getKind() + */ + @Override + public ResultKind getKind() { + return null; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.Result.InjectableResult#getStereotypes(javax.lang.model.element.Element) + */ + @Override + public List getAllStereotypes( Element element ) { + return WebBeansModelProviderImpl.getAllStereotypes(element, + getHelper().getHelper()); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.Result.InjectableResult#getStereotypes(javax.lang.model.element.Element) + */ + @Override + public List getStereotypes( Element element ) { + return InterceptorsResultImpl.getStereotypes(element, getHelper() ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.Result.InjectableResult#isAlternative(javax.lang.model.element.Element) + */ + @Override + public boolean isAlternative( Element element ) { + if (hasAlternative(element)){ + return true; + } + for (AnnotationMirror annotationMirror : getAllStereotypes(element)) { + DeclaredType annotationType = annotationMirror.getAnnotationType(); + if ( hasAlternative( annotationType.asElement()) ){ + return true; + } + } + return false; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.Result.ResolutionResult#hasAlternative(javax.lang.model.element.Element) + */ + @Override + public boolean hasAlternative( Element element ){ + List annotations = getController(). + getElements().getAllAnnotationMirrors(element); + return getHelper().hasAnnotation(annotations, ALTERNATIVE); + } + + AnnotationModelHelper getHelper(){ + return myHelper; + } + + private CompilationController getController(){ + return getHelper().getCompilationController(); + } + + private Set myDeclaredTypes; + private Set myProductions; + private final AnnotationModelHelper myHelper; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/model/spi/WebBeansModelProvider.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/model/spi/WebBeansModelProvider.java new file mode 100644 index 000000000000..23f8fb548845 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/model/spi/WebBeansModelProvider.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model.spi; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.modules.jakarta.web.beans.api.model.BeanArchiveType; +import org.netbeans.modules.jakarta.web.beans.api.model.CdiException; +import org.netbeans.modules.jakarta.web.beans.api.model.InjectionPointDefinitionError; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.api.model.InterceptorsResult; + + +/** + * @author ads + * + */ +public interface WebBeansModelProvider { + + DependencyInjectionResult lookupInjectables( VariableElement element , DeclaredType parentType, AtomicBoolean cancel); + + boolean isDynamicInjectionPoint( VariableElement element ); + + boolean isInjectionPoint( VariableElement element ) throws InjectionPointDefinitionError; + + List getQualifiers( Element element , boolean all ); + + List getNamedElements(AtomicBoolean cancel); + + String getName( Element element); + + List getObservers( VariableElement element, + DeclaredType parentType); + + List getEventInjectionPoints( ExecutableElement element, + DeclaredType parentType); + + VariableElement getObserverParameter( ExecutableElement element); + + String getScope( Element element ) throws CdiException; + + CompilationController getCompilationController(); + + TypeMirror resolveType( String fqn); + + boolean hasImplicitDefaultQualifier( Element element ); + + Collection getDecorators( TypeElement element ); + + InterceptorsResult getInterceptors( Element element ); + + Collection getInterceptorBindings( Element element ); + + BeanArchiveType getBeanArchiveType(); + + boolean isCdi11OrLater(); +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/model/spi/WebBeansModelProviderFactory.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/model/spi/WebBeansModelProviderFactory.java new file mode 100644 index 000000000000..27dfb8b0023d --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/model/spi/WebBeansModelProviderFactory.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model.spi; + +import org.netbeans.modules.jakarta.web.beans.api.model.AbstractModelImplementation; + + +/** + * @author ads + * + */ +public interface WebBeansModelProviderFactory { + + WebBeansModelProvider createWebBeansModelProvider( AbstractModelImplementation model); +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/BindingsPanel.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/BindingsPanel.java new file mode 100644 index 000000000000..7ebf0ef74bf0 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/BindingsPanel.java @@ -0,0 +1,492 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Name; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.swing.tree.TreePath; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelException; +import org.netbeans.modules.jakarta.web.beans.api.model.CdiException; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.api.model.Result; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy.InspectActionId; +import org.netbeans.modules.jakarta.web.beans.navigation.actions.WebBeansActionHelper; + + +/** + * @author ads + * + */ +public class BindingsPanel extends CDIPanel { + + private static final long serialVersionUID = 1230555367053797509L; + + static final String NON_BINDING_MEMBER_ANNOTATION = + "jakarta.enterprise.inject.NonBinding"; // NOI18N + + static final String DEFAULT = "Default"; // NOI18N + + static final String DEFAULT_QUALIFIER_ANNOTATION = + "jakarta.enterprise.inject."+DEFAULT; // NOI18N + + public BindingsPanel( final Object[] subject, MetadataModel metaModel, + WebBeansModel model, JavaHierarchyModel treeModel, Result result ) + { + super(treeModel); + + myModel = metaModel; + + myResult = result; + setVisibleScope(result instanceof DependencyInjectionResult.ResolutionResult); + setVisibleStereotypes( result != null ); + + if ( model == null ){ + try { + metaModel.runReadAction( new MetadataModelAction() { + @Override + public Void run( WebBeansModel model ) throws Exception { + initCDIContext( subject, model ); + return null; + } + }); + } + + catch (MetadataModelException e) { + Logger.getLogger( CDIPanel.class.getName()). + log( Level.WARNING, e.getMessage(), e); + } catch (IOException e) { + Logger.getLogger( CDIPanel.class.getName()). + log( Level.WARNING, e.getMessage(), e); + } + } + else { + initCDIContext( subject, model ); + } + } + + BindingsPanel( Object[] subject, MetadataModel metaModel, + WebBeansModel model, JavaHierarchyModel treeModel ) + { + this(subject, metaModel, model, treeModel, null); + } + + protected void setVisibleScope( boolean visible ){ + getScopeComponent().setVisible(visible); + getScopeLabel().setVisible( visible ); + } + + protected void setVisibleStereotypes( boolean visible ){ + getStereotypeLabel().setVisible(visible); + getStereotypesComponent().setVisible( visible ); + } + + protected void setContextElement( Element context, + CompilationController controller ) + { + TypeMirror typeMirror = context.asType(); + setContextType(typeMirror, controller ); + } + + protected void setContextType( TypeMirror typeMirror, + CompilationController controller) + { + fillElementType(typeMirror, myShortElementName, myFqnElementName, controller); + } + + /* + * Dialog shows element tree. Bindings (qualifiers) and type are shown for selected + * node in this tree. This method is used to access an element which + * contains bindings (qualifiers) and type. + * This method is required for derived classes which wants to reuse + * functionality of this class. Such classes context element + * could be without required annotations and type (F.e. observer method. + * It is used as start point for finding its observer parameter ). + */ + protected Element getSelectedQualifiedElement( Element context , + WebBeansModel model ) + { + return context; + } + + /* + * Normally the subject element is context element ( f.e. injection point ). + * In this case this method returns exactly this element + * from its context. + * Subclasses could override this behavior to return some other + * element . This element will be used for showing type and bindings (qualifiers). + */ + protected Element getSubjectElement ( Element context , + WebBeansModel model) + { + return context; + } + + @Override + protected void showSelectedCDI() { + getSelectedBindingsComponent().setToolTipText(null); + TreePath treePath = getJavaTree().getSelectionPath(); + if (treePath != null) { + Object node = treePath.getLastPathComponent(); + if (node instanceof InjectableTreeNode) { + final ElementHandle elementHandle = + ((InjectableTreeNode)node).getElementHandle(); + try { + getModel().runReadAction( new MetadataModelAction() { + + @Override + public Void run( WebBeansModel model ) throws Exception { + doShowSelectedCDI(elementHandle, model); + return null; + } + + }); + } + + catch (MetadataModelException e) { + Logger.getLogger( CDIPanel.class.getName() ). + log( Level.WARNING, e.getMessage(), e); + } catch (IOException e) { + Logger.getLogger( CDIPanel.class.getName() ). + log( Level.WARNING, e.getMessage(), e); + } + getSelectedBindingsComponent().setCaretPosition(0); + getSelectedBindingsComponent().setToolTipText(((JavaElement)node).getTooltip()); + } + } + } + + @Override + protected void reloadSubjectElement(){ + if ( showFqns() ) { + getInitialBindingsComponent().setText( getFqnBindings() ); + getInitialElement().setText(getFqnElementName().toString()); + } + else { + getInitialBindingsComponent().setText( getShortBindings() ); + getInitialElement().setText( getShortElementName().toString()); + } + } + + protected StringBuilder getShortElementName(){ + return myShortElementName; + } + + protected StringBuilder getFqnElementName(){ + return myFqnElementName; + } + + protected String getFqnBindings(){ + return myFqnBindings; + } + + protected String getShortBindings(){ + return myShortBindings; + } + + protected void setFqnBindings( String bindings ){ + myFqnBindings = bindings; + } + + protected void setShortBindings( String bindings ){ + myShortBindings = bindings; + } + + protected void initBindings( WebBeansModel model, Element element ) { + List qualifiers = model.getQualifiers( element , true ); + + StringBuilder fqnBuilder = new StringBuilder(); + StringBuilder builder = new StringBuilder(); + if ( model.hasImplicitDefaultQualifier(element)){ + fqnBuilder.append('@'); + builder.append('@'); + fqnBuilder.append(DEFAULT_QUALIFIER_ANNOTATION); + builder.append(DEFAULT); + fqnBuilder.append(", "); // NOI18N + builder.append(", "); // NOI18N + } + + for (AnnotationMirror annotationMirror : qualifiers) { + appendAnnotationMirror(annotationMirror, fqnBuilder, true ); + appendAnnotationMirror(annotationMirror, builder, false ); + } + if ( fqnBuilder.length() >0 ){ + myFqnBindings = fqnBuilder.substring(0 , fqnBuilder.length() -2 ); + myShortBindings = builder.substring(0 , builder.length() -2 ); + } + else { + // this should never happens actually. + myFqnBindings = ""; + myShortBindings = ""; + } + if ( showFqns() ) { + getInitialBindingsComponent().setText( myFqnBindings ); + } + else { + getInitialBindingsComponent().setText( myShortBindings ); + } + } + + protected void appendAnnotationMirror( AnnotationMirror mirror , StringBuilder builder , + boolean isFqn ) + { + DeclaredType type = mirror.getAnnotationType(); + Element annotation = type.asElement(); + + builder.append('@'); + String annotationName ; + if ( isFqn ) { + annotationName= ( annotation instanceof TypeElement )? + ((TypeElement)annotation).getQualifiedName().toString() : + annotation.getSimpleName().toString(); + } + else { + annotationName = annotation.getSimpleName().toString(); + } + + builder.append( annotationName ); + + appendBindingParamters( mirror , builder ); + + builder.append(", "); // NOI18N + } + + protected void doShowSelectedCDI(ElementHandle elementHandle, + WebBeansModel model ) throws CdiException + { + Element element = elementHandle.resolve( + model.getCompilationController()); + if ( element == null ){ + getSelectedBindingsComponent().setText(""); + } + else { + element = getSelectedQualifiedElement( element, model); + List bindings = + model.getQualifiers(element, true); + StringBuilder builder = new StringBuilder(); + + if ( model.hasImplicitDefaultQualifier(element)){ + builder.append('@'); + if (showFqns() ){ + builder.append(DEFAULT_QUALIFIER_ANNOTATION); + } + else { + builder.append(DEFAULT); + } + builder.append(", "); // NOI18N + } + + for (AnnotationMirror annotationMirror : bindings) { + appendAnnotationMirror(annotationMirror, builder, showFqns() ); + } + String bindingsString = ""; + if ( builder.length() >0 ){ + bindingsString = builder.substring(0 , + builder.length() -2 ); + } + getSelectedBindingsComponent().setText( bindingsString); + setScope(model, element); + setStereotypes(model, element); + } + } + + protected void setStereotypes( WebBeansModel model, Element element ) + throws CdiException + { + if (getResult() != null) { + List stereotypes = getResult().getAllStereotypes( + element); + if (stereotypes.isEmpty()) { + getStereotypesComponent().setText(""); + return; + } + StringBuilder text = new StringBuilder(); + boolean isFqn = showFqns(); + for (AnnotationMirror stereotype : stereotypes) { + appendAnnotationMirror(stereotype, text, isFqn); + } + getStereotypesComponent().setText(text.substring(0, text.length() - 2)); + } + } + + protected void setScope( WebBeansModel model, Element element ) + throws CdiException + { + if (getResult() instanceof DependencyInjectionResult.ResolutionResult) { + String scope = model.getScope(element); + if (scope == null) { + return; + } + String text = ""; + if (showFqns()) { + text = "@" + scope; // NOI8N + } + else { + TypeMirror scopeType = model.resolveType(scope); + if (scopeType != null) { + Element scopeElement = model.getCompilationController() + .getTypes().asElement(scopeType); + if (scopeElement instanceof TypeElement) { + Name name = ((TypeElement) scopeElement) + .getSimpleName(); + text = "@" + name.toString(); + } + } + } + getScopeComponent().setText(text); + } + } + + private void initCDIContext( Object[] subject, WebBeansModel model ) { + Element element = null; + if ( subject[2] == InspectActionId.INJECTABLES_CONTEXT ){ + element = WebBeansActionHelper.findVariable(model, subject); + } + else { + element = ((ElementHandle)subject[0]).resolve( + model.getCompilationController()); + } + Element context = getSubjectElement(element, model); + if ( context == null ){ + return; + } + + myShortElementName = new StringBuilder(); + myFqnElementName = new StringBuilder(); + setContextElement(context, model.getCompilationController()); + + initBindings(model, context); + + reloadSubjectElement(); + } + + private void appendBindingParamters( AnnotationMirror mirror, + StringBuilder builder ) + { + Map + elementValues = mirror.getElementValues(); + StringBuilder params = new StringBuilder(); + for ( Entry + entry : elementValues.entrySet()) + { + ExecutableElement key = entry.getKey(); + AnnotationValue value = entry.getValue(); + List annotationMirrors = + key.getAnnotationMirrors(); + boolean nonBinding = false; + for (AnnotationMirror annotationMirror : annotationMirrors) { + DeclaredType annotationType = annotationMirror.getAnnotationType(); + Element element = annotationType.asElement(); + if ( ( element instanceof TypeElement ) && + ((TypeElement)element).getQualifiedName(). + contentEquals(NON_BINDING_MEMBER_ANNOTATION)) + { + nonBinding = true; + break; + } + } + if ( !nonBinding ){ + params.append( key.getSimpleName().toString() ); + params.append( "=" ); // NOI18N + if ( value.getValue() instanceof String ){ + params.append('"'); + params.append( value.getValue().toString()); + params.append('"'); + } + else { + params.append( value.getValue().toString()); + } + params.append(", "); // NOI18N + } + } + if ( params.length() >0 ){ + builder.append( "(" ); // NOI18N + builder.append( params.substring(0 , params.length() -2 )); + builder.append( ")" ); // NOI18N + } + } + + private Result getResult() { + return myResult; + } + + private MetadataModel getModel(){ + return myModel; + } + + static void fillElementType( TypeMirror typeMirror, StringBuilder shortName, + StringBuilder fqnName , CompilationController controller) + { + if ( typeMirror.getKind().isPrimitive()){ + shortName.append( typeMirror.getKind().toString().toLowerCase()); + fqnName.append( shortName ); + return; + } + if ( typeMirror.getKind() == TypeKind.ARRAY ){ + fillArrayType( typeMirror , shortName, fqnName , controller ); + shortName = shortName.append("[]"); // NOI18N + fqnName = fqnName.append("[]"); // NOI18N + } + Element element = controller.getTypes().asElement( typeMirror ); + if ( element != null ){ + fqnName.append( (element instanceof TypeElement )? + ((TypeElement)element).getQualifiedName().toString() : + element.getSimpleName().toString()); + shortName.append(element.getSimpleName().toString()); + } + } + + static void fillArrayType( TypeMirror typeMirror, StringBuilder shortName, + StringBuilder fqnName , CompilationController controller ) + { + TypeMirror componentType = ((ArrayType)typeMirror).getComponentType(); + fillElementType(componentType, shortName , fqnName , controller); + } + + private StringBuilder myFqnElementName; + private StringBuilder myShortElementName; + + private String myFqnBindings; + private String myShortBindings; + + private MetadataModel myModel; + + private Result myResult; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/Bundle.properties b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/Bundle.properties new file mode 100644 index 000000000000..3d34a4ab9d99 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/Bundle.properties @@ -0,0 +1,112 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +LBL_WaitNode=Please Wait... + +LABEL_filtersLabel=Filters: +ACSN_Filters=Filters +ACSD_Filters=Filter label +LABEL_Close=C&lose +ACSN_Close=Close button +ACSD_Close=Closes dialog +LABEL_filterLabel=&Filter: +ACSN_TextFilter=Text filter. +ACSD_TextFilter=Applies filter by text +ACSD_TextFieldFilter=Type a regular expression to filter the items. ("?" matches any character, "*" matches any string; a trailing "*" is automatically appended) +LABEL_caseSensitiveFilterCheckBox=&Case sensitive +LBL_Bindings=Injection Point &Qualifiers: +LBL_Policies=&Policies: +LBL_Type=Injection Point &Type: +ACSN_Bindings=Injection point qualifiers +ACSD_Bindnigs=Shows qualifiers for chosen injection point +ACSN_Type=Injection point type +ACSD_Type=Shows type of chosen injection point +LBL_CurrentElementBindings=Q&ualifiers: +LBL_InjectableBindings=Eligible for injection element qualifiers : +ACSN_InjectableBindings=Eligible for injection element's qualifiers +ACSD_InjectableBindnigs=Shows all qualifiers for chosen element eligible for injection. +ACSD_InjectableHierarchy=Eligible for injection elements hierarchy +TOOLTIP_filterTextField=Type a regular expression to filter the items. ("?" matches any character, "*" matches any string; a trailing "*" is automatically appended) +TOOLTIP_showFQNToggleButton=Show fully qualified names (Alt+Q) +TOOLTIP_expandAll=Expand All (Alt+E) +ACSN_CaseSensitive=Case sensitive +caseSensitiveFilterCheckBox_ACSD=Switches Filter case sensitivity + +# Doc scroll pane +ACSN_DocScrollPane=Javadoc View +ACSD_DocScrollPane=Javadoc View +HINT_doc_browser_back_button=Go to previous page +HINT_doc_browser_forward_button=Go to next page +HINT_doc_browser_show_web_button=Show documentation in external web browser +HINT_doc_browser_goto_source_button=Open source in editor + +MSG_CouldNotOpenElement=Could not open element {0}. + +LBL_EventType=&Event Type: +ACSN_EventType=Event type +ACSD_EventType=Shows type of chosen event + +LBL_EventQualifiers=Event &Qualifiers: +ACSN_EventQualifiers=Event qualifiers +ACSD_EventQualifiers=Shows qualifiers for chosen event + +LBL_ObservedEventType=Observed &Event type: +ACSN_ObservedEventType=Observed event type +ACSD_ObservedEventType=Shows type of event for chosen observer + +LBL_ObservedEventQualifiers=Observed Event &Qualifiers: +ACSN_ObservedEventQualifiers=Event qualifiers +ACSD_ObservedEventQualifiers=Shows qualifiers of event for chosen observer +LBL_Scope=&Scope: +ACSN_Scope=Eligible for injection element's scope +ACSD_Scope=Shows scope for chosen eligible for injection element +LBL_Stereotypes=Stere&otypes: +ACSN_Stereotypes=Eligible for injection element's stereotypes +ACSD_Stereotypes=Shows all stereotypes for chosen eligible for injection element + +LBL_InterceptedElement=Intercepted &Element: +ACSN_InterceptedElement=Intercepted element +ACSD_InterceptedElement=Shows chosen element + +LBL_InterceptorBindings=Interceptor &Bindings: +ACSN_InterceptorBindings=Interceptor bindings +ACSD_InterceptorBindings=Shows all interceptor bindings for chosen element + +LBL_SelectedInterceptorBindings=&Interceptor\'s Interceptor Bindings: +ACSN_SelectedInterceptorBindings=Interceptor bindings of interceptor +ACSD_SelectedInterceptorBindings=Shows interceptor bindings of interceptor + +LBL_IStereotypes=Interceptor's Stere&otypes: +ACSN_IStereotypes=Interceptor's stereotypes +ACSD_IStereotypes=Shows all stereotypes for chosen interceptor + +LBL_DecoratedElement=Decorated &Element: +ACSN_DecoratedElement=Decorated element +ACSD_DecoratedElement=Shows chosen element + +LBL_DecoratorQualifiers=Element &Qualifiers: +ACSN_DecoratorQualifiers=Element qualifiers +ACSD_DecoratorQualifiers=Shows chosen element qualifiers + +LBL_SelectedDecoratorQualifiers=Decorator Q&ualifiers: +ACSN_SelectedDecoratorQualifiers=Decorator qualifiers +ACSD_SelectedDecoratorQualifiers=Shows qualifiers of chosen decorator + +LBL_SelectedDelegateType=Decorator Delegate &Type: +ACSN_SelectedDelegateType=Decorator delegate type: +ACSD_SelectedDelegateType=Shows type of delegate injection point + diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/CDIPanel.form b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/CDIPanel.form new file mode 100644 index 000000000000..8e1f2ed8fe54 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/CDIPanel.form @@ -0,0 +1,474 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/CDIPanel.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/CDIPanel.java new file mode 100644 index 000000000000..c63be1e5b11d --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/CDIPanel.java @@ -0,0 +1,855 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Point; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Name; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JEditorPane; +import javax.swing.JLabel; +import javax.swing.JRootPane; +import javax.swing.JTree; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; +import javax.swing.ToolTipManager; +import javax.swing.UIManager; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelException; +import org.netbeans.modules.jakarta.web.beans.api.model.CdiException; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult.ResolutionResult; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.navigation.actions.WebBeansActionHelper; +import org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy.InspectActionId; +import org.openide.util.ImageUtilities; +import org.openide.util.NbBundle; +import org.openide.util.RequestProcessor; + +/** + * Based on org.netbeans.modules.java.navigation.JavaHierarchyPanel + * + * @author ads + * + */ +abstract class CDIPanel extends javax.swing.JPanel { + + private static final long serialVersionUID = 9033410521614864413L; + + public static final Icon FQN_ICON = ImageUtilities.loadImageIcon( + "org/netbeans/modules/java/navigation/resources/fqn.gif", false); // NOI18N + + public static final Icon EXPAND_ALL_ICON = ImageUtilities.loadImageIcon( + "org/netbeans/modules/java/navigation/resources/expandall.gif", false); // NOI18N + + private static TreeModel pleaseWaitTreeModel; + static + { + DefaultMutableTreeNode root = new DefaultMutableTreeNode(); + root.add(new DefaultMutableTreeNode(NbBundle.getMessage( + CDIPanel.class, "LBL_WaitNode"))); // NOI18N + pleaseWaitTreeModel = new DefaultTreeModel(root); + } + + CDIPanel(JavaHierarchyModel treeModel ) { + initComponents(); + myJavaHierarchyModel = treeModel; + + // disable filtering for now: list of injectables will be always short + mySeparator.setVisible(false); + myFilterLabel.setVisible(false); + myFilterTextField.setVisible(false); + myCaseSensitiveFilterCheckBox.setVisible(false); + + myDocPane = new DocumentationScrollPane( true ); + mySplitPane.setRightComponent( myDocPane ); + mySplitPane.setDividerLocation( + WebBeansNavigationOptions.getHierarchyDividerLocation()); + + ToolTipManager.sharedInstance().registerComponent(myJavaHierarchyTree); + ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false); + + myCaseSensitiveFilterCheckBox.setSelected( + WebBeansNavigationOptions.isCaseSensitive()); + myShowFQNToggleButton.setSelected( + WebBeansNavigationOptions.isShowFQN()); + + myJavaHierarchyTree.getSelectionModel().setSelectionMode( + TreeSelectionModel.SINGLE_TREE_SELECTION); + myJavaHierarchyTree.setRootVisible(false); + myJavaHierarchyTree.setShowsRootHandles(true); + myJavaHierarchyTree.setCellRenderer(new JavaTreeCellRenderer()); + + myJavaHierarchyTree.setModel(treeModel); + + registerKeyboardAction( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + close(); + } + }, + KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true), + JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + + initListeners(); + } + + @Override + public void addNotify() { + super.addNotify(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + reload(); + myFilterTextField.requestFocusInWindow(); + } + }); + } + + @Override + public void removeNotify() { + WebBeansNavigationOptions.setHierarchyDividerLocation( + mySplitPane.getDividerLocation()); + myDocPane.setData( null ); + super.removeNotify(); + } + + protected abstract void showSelectedCDI(); + + protected abstract void reloadSubjectElement(); + + // Hack to allow showing of Help window when F1 or HELP key is pressed. + @Override + protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, + boolean pressed) + { + if (e.getKeyCode() == KeyEvent.VK_F1 || e.getKeyCode() == KeyEvent.VK_HELP) { + JComponent rootPane = SwingUtilities.getRootPane(this); + if (rootPane != null) { + rootPane.putClientProperty(ResizablePopup.HELP_COOKIE, Boolean.TRUE); + } + } + return super.processKeyBinding(ks, e, condition, pressed); + } + + protected JLabel getSubjectElementLabel(){ + return mySubjectElementbl; + } + + protected JEditorPane getInitialElement(){ + return mySubjectElement; + } + + protected JLabel getSubjectBindingsLabel(){ + return myBindingLbl; + } + + protected JLabel getSelectedBindingsLbl(){ + return mySelectedBindingLbl; + } + + protected JEditorPane getSelectedBindingsComponent(){ + return mySelectedBindings; + } + + protected JTree getJavaTree(){ + return myJavaHierarchyTree; + } + + protected boolean showFqns(){ + return myShowFQNToggleButton.isSelected(); + } + + protected JEditorPane getScopeComponent(){ + return myScope; + } + + protected JLabel getScopeLabel() { + return myScopeLabel; + } + + protected JEditorPane getStereotypesComponent(){ + return myStereotypes; + } + + protected JLabel getStereotypeLabel() { + return myStereotypesLbl; + } + + protected JEditorPane getInitialBindingsComponent(){ + return myBindings; + } + + protected JLabel getStereotypesLabel(){ + return myStereotypesLbl; + } + + protected JLabel getSelectedBindingsLabel(){ + return mySelectedBindingLbl; + } + + private void enterBusy() { + myJavaHierarchyTree.setModel(pleaseWaitTreeModel); + JRootPane rootPane = SwingUtilities.getRootPane(CDIPanel.this); + if (rootPane != null) { + rootPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + } + Window window = SwingUtilities.getWindowAncestor(this); + if (window != null) { + myLastFocusedComponent = window.getFocusOwner(); + } + myFilterTextField.setEnabled(false); + myCaseSensitiveFilterCheckBox.setEnabled(false); + myShowFQNToggleButton.setEnabled(false); + myExpandAllButton.setEnabled(false); + } + + private void leaveBusy() { + myJavaHierarchyTree.setModel(myJavaHierarchyModel); + JRootPane rootPane = SwingUtilities.getRootPane(CDIPanel.this); + if (rootPane != null) { + rootPane.setCursor(Cursor.getDefaultCursor()); + } + myFilterTextField.setEnabled(true); + myCaseSensitiveFilterCheckBox.setEnabled(true); + myShowFQNToggleButton.setEnabled(true); + myExpandAllButton.setEnabled(true); + if (myLastFocusedComponent != null) { + if (myLastFocusedComponent.isDisplayable()) { + myLastFocusedComponent.requestFocusInWindow(); + } + myLastFocusedComponent = null; + } + } + + private void reload() { + enterBusy(); + + WebBeansNavigationOptions.setCaseSensitive(myCaseSensitiveFilterCheckBox.isSelected()); + WebBeansNavigationOptions.setShowFQN(myShowFQNToggleButton.isSelected()); + + RequestProcessor.getDefault().post( + new Runnable() { + @Override + public void run() { + try { + myJavaHierarchyModel.update(); + } finally { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + leaveBusy(); + // expand the tree + for (int row = 0; + row < myJavaHierarchyTree.getRowCount(); row++) + { + myJavaHierarchyTree.expandRow(row); + } + }}); + } + } + }); + } + + private void expandAll() { + SwingUtilities.invokeLater( + new Runnable() { + @Override + public void run() { + JRootPane rootPane = SwingUtilities.getRootPane(CDIPanel.this); + if (rootPane != null) { + rootPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + } + } + } + ); + + SwingUtilities.invokeLater( + new Runnable() { + @Override + public void run() { + try { + // expand the tree + for (int row = 0; row < myJavaHierarchyTree.getRowCount(); row++) { + myJavaHierarchyTree.expandRow(row); + } + selectMatchingRow(); + } finally { + JRootPane rootPane = SwingUtilities.getRootPane(CDIPanel.this); + if (rootPane != null) { + rootPane.setCursor(Cursor.getDefaultCursor()); + } + } + } + } + ); + } + + private void selectMatchingRow() { + myFilterTextField.setForeground(UIManager.getColor("TextField.foreground")); + myJavaHierarchyTree.setSelectionRow(-1); + // select first matching + for (int row = 0; row < myJavaHierarchyTree.getRowCount(); row++) { + Object o = myJavaHierarchyTree.getPathForRow(row).getLastPathComponent(); + if (o instanceof JavaElement) { + String filterText = myFilterTextField.getText(); + if (Utils.patternMatch((JavaElement)o, filterText, + filterText.toLowerCase())) + { + myJavaHierarchyTree.setSelectionRow(row); + myJavaHierarchyTree.scrollRowToVisible(row); + return; + } + } + } + myFilterTextField.setForeground(Color.RED); + } + + private void gotoElement(JavaElement javaToolsJavaElement) { + try { + javaToolsJavaElement.gotoElement(); + } finally { + close(); + } + } + + private void showJavaDoc() { + TreePath treePath = myJavaHierarchyTree.getSelectionPath(); + if (treePath != null) { + Object node = treePath.getLastPathComponent(); + if (node instanceof JavaElement) { + myDocPane.setData( ((JavaElement)node).getJavaDoc() ); + } + } + } + + private void close() { + Window window = SwingUtilities.getWindowAncestor(CDIPanel.this); + if (window != null) { + window.setVisible(false); + } + } + + private void initListeners() { + myFilterTextField.getDocument().addDocumentListener( + new DocumentListener() { + @Override + public void changedUpdate(DocumentEvent e) { + selectMatchingRow(); + } + @Override + public void insertUpdate(DocumentEvent e) { + selectMatchingRow(); + } + @Override + public void removeUpdate(DocumentEvent e) { + selectMatchingRow(); + } + } + ); + + registerKeyboardActions(); + + myCaseSensitiveFilterCheckBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + WebBeansNavigationOptions.setCaseSensitive( + myCaseSensitiveFilterCheckBox.isSelected()); + if (myFilterTextField.getText().trim().length() > 0) { + // apply filters again only if there is some filter text + selectMatchingRow(); + } + } + }); + + myJavaHierarchyTree.addMouseListener( + new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent me) { + Point point = me.getPoint(); + TreePath treePath = myJavaHierarchyTree. + getPathForLocation(point.x, point.y); + if (treePath != null) { + Object node = treePath.getLastPathComponent(); + if (node instanceof JavaElement) { + if (me.getClickCount() == 2){ + gotoElement((JavaElement) node); + } + } + } + } + } + ); + + myJavaHierarchyTree.addTreeSelectionListener(new TreeSelectionListener() { + @Override + public void valueChanged(TreeSelectionEvent e) { + showSelectedCDI(); + showJavaDoc(); + } + }); + + myShowFQNToggleButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + WebBeansNavigationOptions.setShowFQN(myShowFQNToggleButton.isSelected()); + myJavaHierarchyModel.fireTreeNodesChanged(); + reloadSubjectElement(); + showSelectedCDI(); + } + }); + + myExpandAllButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + expandAll(); + } + }); + + myCloseButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + close(); + } + }); + } + private void registerKeyboardActions() { + ActionListener listener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + Utils.firstRow(myJavaHierarchyTree); + } + }; + + myFilterTextField.registerKeyboardAction( listener, + KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0, false), + JComponent.WHEN_FOCUSED); + + myBindings.registerKeyboardAction(listener, + KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0, false), + JComponent.WHEN_FOCUSED); + + listener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + Utils.previousRow(myJavaHierarchyTree); + } + }; + myFilterTextField.registerKeyboardAction(listener, + KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), + JComponent.WHEN_FOCUSED); + + myBindings.registerKeyboardAction( listener , + KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), + JComponent.WHEN_FOCUSED); + + listener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + Utils.nextRow(myJavaHierarchyTree); + } + }; + myFilterTextField.registerKeyboardAction(listener, + KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), + JComponent.WHEN_FOCUSED); + + myBindings.registerKeyboardAction(listener, + KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), + JComponent.WHEN_FOCUSED); + + listener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + Utils.lastRow(myJavaHierarchyTree); + } + }; + myFilterTextField.registerKeyboardAction(listener, + KeyStroke.getKeyStroke(KeyEvent.VK_END, 0, false), + JComponent.WHEN_FOCUSED); + + myBindings.registerKeyboardAction(listener, + KeyStroke.getKeyStroke(KeyEvent.VK_END, 0, false), + JComponent.WHEN_FOCUSED); + + myBindings.putClientProperty( + "HighlightsLayerExcludes", // NOI18N + "^org\\.netbeans\\.modules\\.editor\\.lib2\\.highlighting\\.CaretRowHighlighting$" // NOI18N + ); + + myFilterTextField.registerKeyboardAction( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + TreePath treePath = myJavaHierarchyTree.getSelectionPath(); + if (treePath != null) { + Object node = treePath.getLastPathComponent(); + if (node instanceof JavaElement) { + gotoElement((JavaElement) node); + } + } + } + }, + KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true), + JComponent.WHEN_FOCUSED); + + myFilterTextField.registerKeyboardAction( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + Component view = myDocPane.getViewport().getView(); + if (view instanceof JEditorPane) { + JEditorPane editorPane = (JEditorPane) view; + ActionListener actionForKeyStroke = + editorPane.getActionForKeyStroke( + KeyStroke.getKeyStroke( + KeyEvent.VK_PAGE_UP, 0, false)); + actionForKeyStroke.actionPerformed( + new ActionEvent(editorPane, + ActionEvent.ACTION_PERFORMED, "")); + } + } + }, + KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, + KeyEvent.SHIFT_MASK, false), + JComponent.WHEN_FOCUSED); + myFilterTextField.registerKeyboardAction( + new ActionListener() { + private boolean firstTime = true; + @Override + public void actionPerformed(ActionEvent actionEvent) { + Component view = myDocPane.getViewport().getView(); + if (view instanceof JEditorPane) { + JEditorPane editorPane = (JEditorPane) view; + ActionListener actionForKeyStroke = + editorPane.getActionForKeyStroke( + KeyStroke.getKeyStroke( + KeyEvent.VK_PAGE_DOWN, 0, false)); + actionEvent = new ActionEvent(editorPane, + ActionEvent.ACTION_PERFORMED, ""); + actionForKeyStroke.actionPerformed(actionEvent); + if (firstTime) { + actionForKeyStroke.actionPerformed(actionEvent); + firstTime = false; + } + } + } + }, + KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, + KeyEvent.SHIFT_MASK, false), + JComponent.WHEN_FOCUSED); + + myJavaHierarchyTree.registerKeyboardAction( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + TreePath treePath = myJavaHierarchyTree.getLeadSelectionPath(); + if (treePath != null) { + Object node = treePath.getLastPathComponent(); + if (node instanceof JavaElement) { + gotoElement((JavaElement) node); + } + } + } + }, + KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true), + JComponent.WHEN_FOCUSED); + + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + mySplitPane = new javax.swing.JSplitPane(); + myJavaHierarchyTreeScrollPane = new javax.swing.JScrollPane(); + myJavaHierarchyTree = new javax.swing.JTree(); + myFilterLabel = new javax.swing.JLabel(); + myFilterTextField = new javax.swing.JTextField(); + myCaseSensitiveFilterCheckBox = new javax.swing.JCheckBox(); + myFiltersLabel = new javax.swing.JLabel(); + myCloseButton = new javax.swing.JButton(); + myFiltersToolbar = new NoBorderToolBar(); + myShowFQNToggleButton = new javax.swing.JToggleButton(); + myExpandAllButton = new javax.swing.JButton(); + mySeparator = new javax.swing.JSeparator(); + myBindings = new javax.swing.JEditorPane(); + myBindingLbl = new javax.swing.JLabel(); + mySubjectElement = new javax.swing.JEditorPane(); + mySubjectElementbl = new javax.swing.JLabel(); + mySelectedBindings = new javax.swing.JEditorPane(); + mySelectedBindingLbl = new javax.swing.JLabel(); + myScopeLabel = new javax.swing.JLabel(); + myScope = new javax.swing.JEditorPane(); + myStereotypesLbl = new javax.swing.JLabel(); + myStereotypes = new javax.swing.JEditorPane(); + + setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0))); + + mySplitPane.setDividerLocation(300); + + myJavaHierarchyTreeScrollPane.setBorder(null); + myJavaHierarchyTreeScrollPane.setViewportView(myJavaHierarchyTree); + myJavaHierarchyTree.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSD_InjectableHierarchy")); // NOI18N + + mySplitPane.setLeftComponent(myJavaHierarchyTreeScrollPane); + + myFilterLabel.setLabelFor(myFilterTextField); + org.openide.awt.Mnemonics.setLocalizedText(myFilterLabel, org.openide.util.NbBundle.getBundle(CDIPanel.class).getString("LABEL_filterLabel")); // NOI18N + + myFilterTextField.setToolTipText(org.openide.util.NbBundle.getBundle(CDIPanel.class).getString("TOOLTIP_filterTextField")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(myCaseSensitiveFilterCheckBox, org.openide.util.NbBundle.getBundle(CDIPanel.class).getString("LABEL_caseSensitiveFilterCheckBox")); // NOI18N + myCaseSensitiveFilterCheckBox.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0)); + + org.openide.awt.Mnemonics.setLocalizedText(myFiltersLabel, org.openide.util.NbBundle.getMessage(CDIPanel.class, "LABEL_filtersLabel")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(myCloseButton, org.openide.util.NbBundle.getMessage(CDIPanel.class, "LABEL_Close")); // NOI18N + + myFiltersToolbar.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1)); + myFiltersToolbar.setFloatable(false); + myFiltersToolbar.setBorderPainted(false); + myFiltersToolbar.setOpaque(false); + + myShowFQNToggleButton.setIcon(FQN_ICON); + myShowFQNToggleButton.setMnemonic('Q'); + myShowFQNToggleButton.setToolTipText(org.openide.util.NbBundle.getBundle(CDIPanel.class).getString("TOOLTIP_showFQNToggleButton")); // NOI18N + myShowFQNToggleButton.setMargin(new java.awt.Insets(2, 2, 2, 2)); + myFiltersToolbar.add(myShowFQNToggleButton); + + myExpandAllButton.setIcon(EXPAND_ALL_ICON); + myExpandAllButton.setMnemonic('E'); + myExpandAllButton.setToolTipText(org.openide.util.NbBundle.getMessage(CDIPanel.class, "TOOLTIP_expandAll")); // NOI18N + myExpandAllButton.setMargin(new java.awt.Insets(2, 2, 2, 2)); + myFiltersToolbar.add(myExpandAllButton); + + myBindings.setBorder(javax.swing.BorderFactory.createLineBorder(javax.swing.UIManager.getDefaults().getColor("Nb.ScrollPane.Border.color"))); + myBindings.setContentType("text/x-java"); + myBindings.setEditable(false); + + myBindingLbl.setLabelFor(myBindings); + org.openide.awt.Mnemonics.setLocalizedText(myBindingLbl, org.openide.util.NbBundle.getMessage(CDIPanel.class, "LBL_Bindings")); // NOI18N + + mySubjectElement.setBorder(javax.swing.BorderFactory.createLineBorder(javax.swing.UIManager.getDefaults().getColor("Nb.ScrollPane.Border.color"))); + mySubjectElement.setContentType("text/x-java"); + mySubjectElement.setEditable(false); + + mySubjectElementbl.setLabelFor(mySubjectElement); + org.openide.awt.Mnemonics.setLocalizedText(mySubjectElementbl, org.openide.util.NbBundle.getMessage(CDIPanel.class, "LBL_Type")); // NOI18N + + mySelectedBindings.setBorder(javax.swing.BorderFactory.createLineBorder(javax.swing.UIManager.getDefaults().getColor("Nb.ScrollPane.Border.color"))); + mySelectedBindings.setContentType("text/x-java"); + mySelectedBindings.setEditable(false); + + mySelectedBindingLbl.setLabelFor(mySelectedBindings); + org.openide.awt.Mnemonics.setLocalizedText(mySelectedBindingLbl, org.openide.util.NbBundle.getMessage(CDIPanel.class, "LBL_CurrentElementBindings")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(myScopeLabel, org.openide.util.NbBundle.getMessage(CDIPanel.class, "LBL_Scope")); // NOI18N + + myScope.setBorder(javax.swing.BorderFactory.createLineBorder(javax.swing.UIManager.getDefaults().getColor("Nb.ScrollPane.Border.color"))); + myScope.setContentType("text/x-java"); + myScope.setEditable(false); + + org.openide.awt.Mnemonics.setLocalizedText(myStereotypesLbl, org.openide.util.NbBundle.getMessage(CDIPanel.class, "LBL_Stereotypes")); // NOI18N + + myStereotypes.setBorder(javax.swing.BorderFactory.createLineBorder(javax.swing.UIManager.getDefaults().getColor("Nb.ScrollPane.Border.color"))); + myStereotypes.setContentType("text/x-java"); + myStereotypes.setEditable(false); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(mySplitPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 715, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(myFilterLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(myFilterTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 532, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(myCaseSensitiveFilterCheckBox)) + .addComponent(mySeparator, javax.swing.GroupLayout.DEFAULT_SIZE, 715, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(myBindingLbl) + .addComponent(mySubjectElementbl)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(mySubjectElement, javax.swing.GroupLayout.DEFAULT_SIZE, 518, Short.MAX_VALUE) + .addComponent(myBindings, javax.swing.GroupLayout.DEFAULT_SIZE, 518, Short.MAX_VALUE))) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(mySelectedBindingLbl) + .addComponent(myScopeLabel) + .addComponent(myStereotypesLbl) + .addComponent(myFiltersLabel)) + .addGap(28, 28, 28) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addComponent(myFiltersToolbar, javax.swing.GroupLayout.DEFAULT_SIZE, 513, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(myCloseButton)) + .addComponent(mySelectedBindings, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 592, Short.MAX_VALUE) + .addComponent(myScope, javax.swing.GroupLayout.DEFAULT_SIZE, 592, Short.MAX_VALUE) + .addComponent(myStereotypes, javax.swing.GroupLayout.DEFAULT_SIZE, 592, Short.MAX_VALUE)))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(mySubjectElementbl) + .addComponent(mySubjectElement, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(myBindings, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(myBindingLbl)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(mySeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(myFilterLabel) + .addComponent(myFilterTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(myCaseSensitiveFilterCheckBox)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(mySplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 151, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(mySelectedBindingLbl) + .addComponent(mySelectedBindings, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(myScopeLabel) + .addComponent(myScope, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addGroup(layout.createSequentialGroup() + .addComponent(myStereotypes, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(myCloseButton)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addComponent(myStereotypesLbl) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(myFiltersLabel) + .addGap(6, 6, 6)) + .addComponent(myFiltersToolbar, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) + ); + + myFilterLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSN_TextFilter")); // NOI18N + myFilterLabel.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSD_TextFilter")); // NOI18N + myFilterTextField.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSD_TextFieldFilter")); // NOI18N + myCaseSensitiveFilterCheckBox.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSN_CaseSensitive")); // NOI18N + myCaseSensitiveFilterCheckBox.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(CDIPanel.class, "caseSensitiveFilterCheckBox_ACSD")); // NOI18N + myFiltersLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSN_Filters")); // NOI18N + myFiltersLabel.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSD_Filters")); // NOI18N + myCloseButton.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSN_Close")); // NOI18N + myCloseButton.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSD_Close")); // NOI18N + myBindingLbl.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSN_Bindings")); // NOI18N + myBindingLbl.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSD_Bindnigs")); // NOI18N + mySubjectElementbl.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSN_Type")); // NOI18N + mySubjectElementbl.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSD_Type")); // NOI18N + mySelectedBindingLbl.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSN_InjectableBindings")); // NOI18N + mySelectedBindingLbl.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSD_InjectableBindnigs")); // NOI18N + myScopeLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSN_Scope")); // NOI18N + myScopeLabel.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSD_Scope")); // NOI18N + myScope.getAccessibleContext().setAccessibleName(myScopeLabel.getAccessibleContext().getAccessibleName()); + myScope.getAccessibleContext().setAccessibleDescription(myScopeLabel.getAccessibleContext().getAccessibleDescription()); + myStereotypesLbl.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSN_Stereotypes")); // NOI18N + myStereotypesLbl.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(CDIPanel.class, "ACSD_Stereotypes")); // NOI18N + }// //GEN-END:initComponents + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel myBindingLbl; + private javax.swing.JEditorPane myBindings; + private javax.swing.JCheckBox myCaseSensitiveFilterCheckBox; + private javax.swing.JButton myCloseButton; + private javax.swing.JButton myExpandAllButton; + private javax.swing.JLabel myFilterLabel; + private javax.swing.JTextField myFilterTextField; + private javax.swing.JLabel myFiltersLabel; + private javax.swing.JToolBar myFiltersToolbar; + private javax.swing.JTree myJavaHierarchyTree; + private javax.swing.JScrollPane myJavaHierarchyTreeScrollPane; + private javax.swing.JEditorPane myScope; + private javax.swing.JLabel myScopeLabel; + private javax.swing.JLabel mySelectedBindingLbl; + private javax.swing.JEditorPane mySelectedBindings; + private javax.swing.JSeparator mySeparator; + private javax.swing.JToggleButton myShowFQNToggleButton; + private javax.swing.JSplitPane mySplitPane; + private javax.swing.JEditorPane myStereotypes; + private javax.swing.JLabel myStereotypesLbl; + private javax.swing.JEditorPane mySubjectElement; + private javax.swing.JLabel mySubjectElementbl; + // End of variables declaration//GEN-END:variables + + private Component myLastFocusedComponent; + private DocumentationScrollPane myDocPane; + + private JavaHierarchyModel myJavaHierarchyModel; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/DecoratorsModel.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/DecoratorsModel.java new file mode 100644 index 000000000000..91832ac4107f --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/DecoratorsModel.java @@ -0,0 +1,160 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.TypeElement; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.SourceUtils; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelException; +import org.netbeans.modules.jakarta.web.beans.api.model.BeansModel; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.navigation.actions.WebBeansActionHelper; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +public final class DecoratorsModel extends DefaultTreeModel implements + JavaHierarchyModel +{ + + private static final long serialVersionUID = 5096971301097791384L; + + private static final Logger LOG = Logger.getLogger( + DecoratorsModel.class.getName()); + + public DecoratorsModel( Collection decorators , + BeansModel beansModel, CompilationController controller , + MetadataModel model) + { + super(null); + myModel = model; + + myHandles = new ArrayList>( decorators.size()); + myEnabledDecorators = new LinkedHashSet>(); + + LinkedHashSet enabled = WebBeansActionHelper. + getEnabledDecorators( decorators,beansModel, myEnabledDecorators, + controller); + for (TypeElement decorator : decorators ) { + myHandles.add( ElementHandle.create( decorator )); + } + + update( decorators , enabled , controller ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.JavaHierarchyModel#fireTreeNodesChanged() + */ + @Override + public void fireTreeNodesChanged() { + super.fireTreeNodesChanged(this, getPathToRoot((TreeNode)getRoot()), + null, null); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.JavaHierarchyModel#update() + */ + @Override + public void update() { + updateHandles( myHandles , myEnabledDecorators); + } + + private void updateHandles( final List> handles, + final LinkedHashSet> enabled ) + { + try { + getModel().runReadAction( + new MetadataModelAction() { + + @Override + public Void run( WebBeansModel model ) { + List list = new ArrayList( + handles.size()); + LinkedHashSet set = + new LinkedHashSet(); + for (ElementHandle handle : handles) { + TypeElement type = handle.resolve(model + .getCompilationController()); + if (type != null) { + list.add(type); + } + if (enabled.contains(handle)) { + set.add(type); + } + } + update(list, set, model.getCompilationController()); + return null; + } + }); + + return; + } + catch (MetadataModelException e) { + LOG.log(Level.WARNING, e.getMessage(), e); + } + catch (IOException e) { + LOG.log(Level.WARNING, e.getMessage(), e); + } + } + + private void update( Collection foundDecorators, + LinkedHashSet enabled, CompilationController controller ) + { + DefaultMutableTreeNode root = new DefaultMutableTreeNode(); + + LinkedHashSet allDecorators = new LinkedHashSet(); + allDecorators.addAll( enabled ); + allDecorators.addAll( foundDecorators ); + + for (TypeElement type : allDecorators) { + FileObject fileObject = SourceUtils.getFile(ElementHandle + .create(type), controller.getClasspathInfo()); + TypeTreeNode node = new TypeTreeNode(fileObject, type, + !enabled.contains(type ),controller); + root.add( node ); + } + setRoot(root); + } + + private MetadataModel getModel(){ + return myModel; + } + + private MetadataModel myModel; + private List> myHandles; + private LinkedHashSet> myEnabledDecorators; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/DecoratorsPanel.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/DecoratorsPanel.java new file mode 100644 index 000000000000..5ff915da2291 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/DecoratorsPanel.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.util.List; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; +import javax.swing.JEditorPane; +import javax.swing.JLabel; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.openide.awt.Mnemonics; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class DecoratorsPanel extends BindingsPanel { + + private static final long serialVersionUID = -5097678699872215262L; + private static final String DELEGATE = "jakarta.decorator.Delegate"; // NOI18N + + public DecoratorsPanel( Object[] subject, MetadataModel metaModel, + WebBeansModel model, JavaHierarchyModel treeModel ) + { + super(subject, metaModel, model, treeModel); + // use Scope components for showing type of Delegate injectoin point + setVisibleScope( true ); + initUI(); + } + + @Override + protected void setScope( WebBeansModel model, Element element ){ + TypeElement clazz = (TypeElement)element; + List fields = ElementFilter.fieldsIn( + model.getCompilationController().getElements().getAllMembers( clazz)); + VariableElement delegate = null; + for (VariableElement field : fields) { + if( hasDelegate(field, model.getCompilationController())){ + delegate = field; + break; + } + } + TypeMirror delegateType = delegate.asType(); + StringBuilder shortName = new StringBuilder(); + StringBuilder fqnName = new StringBuilder(); + fillElementType(delegateType, shortName, fqnName, model.getCompilationController()); + JEditorPane scopeComponent = getScopeComponent(); + if ( showFqns() ){ + scopeComponent.setText( fqnName.toString() ); + } + else { + scopeComponent.setText( shortName.toString() ); + } + } + + private boolean hasDelegate( Element element , CompilationController controller){ + List allAnnotationMirrors = controller. + getElements().getAllAnnotationMirrors( element); + TypeElement delegate = controller.getElements().getTypeElement( DELEGATE); + if( delegate == null ){ + return false; + } + for (AnnotationMirror annotationMirror : allAnnotationMirrors) { + Element annotation = controller.getTypes().asElement( + annotationMirror.getAnnotationType()); + if ( annotation!= null && annotation.equals( delegate )){ + return true; + } + } + return false; + } + + private void initUI() { + JLabel elementLabel = getSubjectElementLabel(); + Mnemonics.setLocalizedText(elementLabel,NbBundle.getMessage( + ObserversPanel.class, "LBL_DecoratedElement") ); // NOI18N + elementLabel.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSN_DecoratedElement")); // NOI18N + elementLabel.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSD_DecoratedElement")); // NOI18N + + JLabel qualifiers= getSubjectBindingsLabel(); + Mnemonics.setLocalizedText(qualifiers,NbBundle.getMessage( + ObserversPanel.class, "LBL_DecoratorQualifiers") ); // NOI18N + qualifiers.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSN_DecoratorQualifiers")); // NOI18N + qualifiers.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSD_DecoratorQualifiers")); // NOI18N + + JLabel selectedQualifiers = getSelectedBindingsLabel(); + Mnemonics.setLocalizedText(selectedQualifiers,NbBundle.getMessage( + ObserversPanel.class, "LBL_SelectedDecoratorQualifiers") ); // NOI18N + selectedQualifiers.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSN_SelectedDecoratorQualifiers")); // NOI18N + selectedQualifiers.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSD_SelectedDecoratorQualifiers")); // NOI18N + + JLabel scopeLabel = getScopeLabel(); + Mnemonics.setLocalizedText(scopeLabel,NbBundle.getMessage( + ObserversPanel.class, "LBL_SelectedDelegateType") ); // NOI18N + scopeLabel.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSN_SelectedDelegateType")); // NOI18N + scopeLabel.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSD_SelectedDelegateType")); // NOI18N + + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/DocumentationScrollPane.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/DocumentationScrollPane.java new file mode 100644 index 000000000000..87841517e770 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/DocumentationScrollPane.java @@ -0,0 +1,441 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import javax.swing.*; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; +import javax.swing.plaf.TextUI; +import javax.swing.text.Document; +import javax.swing.text.EditorKit; +import javax.swing.text.JTextComponent; +import javax.swing.text.Keymap; +import javax.swing.text.html.HTMLDocument; +import org.netbeans.api.java.source.ui.ElementJavadoc; + +import org.netbeans.editor.*; + +import org.openide.awt.HtmlBrowser; +import org.openide.awt.StatusDisplayer; +import org.openide.util.ImageUtilities; +import org.openide.util.NbBundle; + +/** + * Based on DocumentationScrollPane at java.navigation + * + * @author ads + */ +public class DocumentationScrollPane extends JScrollPane { + + private static final long serialVersionUID = -8672029782033541392L; + + private static final String BACK = "org/netbeans/modules/java/navigation/resources/back.png"; //NOI18N + private static final String FORWARD = "org/netbeans/modules/java/navigation/resources/forward.png"; //NOI18N + private static final String GOTO_SOURCE = "org/netbeans/modules/java/navigation/resources/open_source_in_editor.png"; //NOI18N + private static final String SHOW_WEB = "org/netbeans/modules/java/navigation/resources/open_in_external_browser.png"; //NOI18N + + private static final String JAVADOC_BACK = "javadoc-back"; //NOI18N + private static final String JAVADOC_FORWARD = "javadoc-forward"; //NOI18N + private static final String JAVADOC_OPEN_IN_BROWSER = "javadoc-open-in-browser"; //NOI18N + private static final String JAVADOC_OPEN_SOURCE = "javadoc-open-source"; //NOI18N + + private static final int ACTION_JAVADOC_ESCAPE = 0; + private static final int ACTION_JAVADOC_BACK = 1; + private static final int ACTION_JAVADOC_FORWARD = 2; + private static final int ACTION_JAVADOC_OPEN_IN_BROWSER = 3; + private static final int ACTION_JAVADOC_OPEN_SOURCE = 4; + + private JButton bBack, bForward, bGoToSource, bShowWeb; + private HTMLDocView view; + + // doc browser history + private List history = new ArrayList(5); + private int currentHistoryIndex = -1; + protected ElementJavadoc currentDocumentation = null; + + /** Creates a new instance of ScrollJavaDocPane */ + public DocumentationScrollPane( boolean keepDefaultBorder ) { + super(); + + // Add the completion doc view + //XXX fix bg color + view = new HTMLDocView( getDefaultBackground() ); + view.addHyperlinkListener(new HyperlinkAction()); + setViewportView(view); + getAccessibleContext().setAccessibleName(NbBundle.getMessage(DocumentationScrollPane.class, "ACSN_DocScrollPane")); + getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(DocumentationScrollPane.class, "ACSD_DocScrollPane")); + view.getAccessibleContext().setAccessibleName(NbBundle.getMessage(DocumentationScrollPane.class, "ACSN_DocScrollPane")); + view.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(DocumentationScrollPane.class, "ACSD_DocScrollPane")); + installTitleComponent(); +// installKeybindings(view); + setFocusable(true); + + if( !keepDefaultBorder ) + setBorder( BorderFactory.createEmptyBorder() ); + } + + public void setData(ElementJavadoc doc) { + setData(doc, true); + } + + private void setData(ElementJavadoc doc, boolean clearHistory) { + synchronized (this) { + if ( doc == null || clearHistory ) { + history = new ArrayList(5); + } + } + setDocumentation(doc); + if( null != doc ) + addToHistory(doc); + } + + private ImageIcon resolveIcon(String res){ + return ImageUtilities.loadImageIcon(res, false); + } + + private void installTitleComponent() { + JToolBar toolbar = new JToolBar(); + toolbar.setFloatable(false); + toolbar.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, UIManager.getColor("controlDkShadow"))); //NOI18N + toolbar.setLayout(new GridBagLayout()); + + GridBagConstraints gdc = new GridBagConstraints(); + gdc.gridx = 0; + gdc.gridy = 0; + gdc.anchor = GridBagConstraints.WEST; + ImageIcon icon = resolveIcon(BACK); + if (icon != null) { + bBack = new BrowserButton(icon); + bBack.addMouseListener(new MouseEventListener(bBack)); + bBack.addActionListener(new DocPaneAction(ACTION_JAVADOC_BACK)); + bBack.setEnabled(false); + //bBack.setFocusable(false); + bBack.setContentAreaFilled(false); + bBack.setMargin(new Insets(0, 0, 0, 0)); + bBack.setToolTipText(NbBundle.getMessage(DocumentationScrollPane.class, "HINT_doc_browser_back_button")); //NOI18N + toolbar.add(bBack, gdc); + } + + gdc.gridx = 1; + gdc.gridy = 0; + gdc.anchor = GridBagConstraints.WEST; + icon = resolveIcon(FORWARD); + if (icon != null) { + bForward = new BrowserButton(icon); + bForward.addMouseListener(new MouseEventListener(bForward)); + bForward.addActionListener(new DocPaneAction(ACTION_JAVADOC_FORWARD)); + bForward.setEnabled(false); + //bForward.setFocusable(false); + bForward.setContentAreaFilled(false); + bForward.setToolTipText(NbBundle.getMessage(DocumentationScrollPane.class, "HINT_doc_browser_forward_button")); //NOI18N + bForward.setMargin(new Insets(0, 0, 0, 0)); + toolbar.add(bForward, gdc); + } + + gdc.gridx = 2; + gdc.gridy = 0; + gdc.anchor = GridBagConstraints.WEST; + icon = resolveIcon(SHOW_WEB); + if (icon != null) { + bShowWeb = new BrowserButton(icon); + bShowWeb.addMouseListener(new MouseEventListener(bShowWeb)); + bShowWeb.addActionListener(new DocPaneAction(ACTION_JAVADOC_OPEN_IN_BROWSER)); + bShowWeb.setEnabled(false); + //bShowWeb.setFocusable(false); + bShowWeb.setContentAreaFilled(false); + bShowWeb.setMargin(new Insets(0, 0, 0, 0)); + bShowWeb.setToolTipText(NbBundle.getMessage(DocumentationScrollPane.class, "HINT_doc_browser_show_web_button")); //NOI18N + toolbar.add(bShowWeb, gdc); + } + + gdc.gridx = 3; + gdc.gridy = 0; + gdc.weightx = 1.0; + gdc.anchor = GridBagConstraints.WEST; + icon = resolveIcon(GOTO_SOURCE); + if (icon != null) { + bGoToSource = new BrowserButton(icon); + bGoToSource.addMouseListener(new MouseEventListener(bGoToSource)); + bGoToSource.addActionListener(new DocPaneAction(ACTION_JAVADOC_OPEN_SOURCE)); + bGoToSource.setEnabled(false); + //bGoToSource.setFocusable(false); + bGoToSource.setContentAreaFilled(false); + bGoToSource.setMargin(new Insets(0, 0, 0, 0)); + bGoToSource.setToolTipText(NbBundle.getMessage(DocumentationScrollPane.class, "HINT_doc_browser_goto_source_button")); //NOI18N + toolbar.add(bGoToSource, gdc); + } + setColumnHeaderView(toolbar); + installKeybindings(view); + } + + private synchronized void setDocumentation(ElementJavadoc doc) { + currentDocumentation = doc; + if( null != doc ) { + String text = currentDocumentation.getText(); + URL url = currentDocumentation.getURL(); + if (text != null){ + Document document = view.getDocument(); + document.putProperty(Document.StreamDescriptionProperty, null); + if (url!=null){ + // fix of issue #58658 + if (document instanceof HTMLDocument){ + ((HTMLDocument)document).setBase(url); + } + } + view.setContent(text, null); + } else if (url != null){ + try{ + view.setPage(url); + }catch(IOException ioe){ + StatusDisplayer.getDefault().setStatusText(ioe.toString()); + } + } + bShowWeb.setEnabled(url != null); + bGoToSource.setEnabled(currentDocumentation.getGotoSourceAction() != null); + } else { + bShowWeb.setEnabled( false ); + bGoToSource.setEnabled( false ); + view.setContent("", null);//NOI18N + } + } + + private synchronized void addToHistory(ElementJavadoc doc) { + int histSize = history.size(); + for (int i = currentHistoryIndex + 1; i < histSize; i++){ + history.remove(history.size() - 1); + } + history.add(doc); + currentHistoryIndex = history.size() - 1; + if (currentHistoryIndex > 0) + bBack.setEnabled(true); + bForward.setEnabled(false); + } + + private synchronized void backHistory() { + if (currentHistoryIndex > 0 && currentHistoryIndex <= history.size()) { + currentHistoryIndex--; + setDocumentation(history.get(currentHistoryIndex)); + if (currentHistoryIndex == 0) + bBack.setEnabled(false); + bForward.setEnabled(true); + } + } + + private synchronized void forwardHistory(){ + if (currentHistoryIndex 0) { + ret = keys; + } + } + } + } + } + return ret; + } + + private void registerKeybinding(int action, String actionName, KeyStroke stroke, String editorActionName, JTextComponent component){ + KeyStroke[] keys = findEditorKeys(editorActionName, stroke, component); + for (int i = 0; i < keys.length; i++) { + view.getInputMap().put(keys[i], actionName); + } + view.getActionMap().put(actionName, new DocPaneAction(action)); + } + + private void installKeybindings(JTextComponent component) { + // Register javadoc back key + registerKeybinding(ACTION_JAVADOC_BACK, JAVADOC_BACK, + KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.ALT_MASK), + null, component); + + // Register javadoc forward key + registerKeybinding(ACTION_JAVADOC_FORWARD, JAVADOC_FORWARD, + KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.ALT_MASK), + null, component); + + // Register open in external browser key + registerKeybinding(ACTION_JAVADOC_OPEN_IN_BROWSER, JAVADOC_OPEN_IN_BROWSER, + KeyStroke.getKeyStroke(KeyEvent.VK_F1, KeyEvent.ALT_MASK | KeyEvent.SHIFT_MASK), + null, component); + + // Register open the source in editor key + registerKeybinding(ACTION_JAVADOC_OPEN_SOURCE, JAVADOC_OPEN_SOURCE, + KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.ALT_MASK | KeyEvent.CTRL_MASK), + null, component); + + // Register movement keystrokes to be reachable through Shift+ + mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)); + mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)); + mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0)); + mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0)); + mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, KeyEvent.CTRL_MASK)); + mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_END, KeyEvent.CTRL_MASK)); + mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0)); + mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)); + } + + private void mapWithShift(KeyStroke key) { + InputMap inputMap = view.getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + Object actionKey = inputMap.get(key); + if (actionKey != null) { + key = KeyStroke.getKeyStroke(key.getKeyCode(), key.getModifiers() | InputEvent.SHIFT_MASK); + view.getInputMap().put(key, actionKey); + } + } + + private Color getDefaultBackground() { + Color bgColor = new JEditorPane().getBackground(); + bgColor = new Color( + Math.max(bgColor.getRed() - 8, 0 ), + Math.max(bgColor.getGreen() - 8, 0 ), + bgColor.getBlue()); + + return bgColor; + } + + private static class BrowserButton extends JButton { + private static final long serialVersionUID = 3572084819036272122L; + + public BrowserButton(Icon icon){ + super(icon); + setBorderPainted(false); + //setFocusPainted(false); + } + + public @Override void setEnabled(boolean b) { + super.setEnabled(b); + } + } + + private static class MouseEventListener extends MouseAdapter { + private JButton button; + + MouseEventListener(JButton button) { + this.button = button; + } + + public @Override void mouseEntered(MouseEvent ev) { + if (button.isEnabled()){ + button.setContentAreaFilled(true); + button.setBorderPainted(true); + } + } + public @Override void mouseExited(MouseEvent ev) { + button.setContentAreaFilled(false); + button.setBorderPainted(false); + } + } + + private class HyperlinkAction implements HyperlinkListener { + + public void hyperlinkUpdate(HyperlinkEvent e) { + if (e != null && HyperlinkEvent.EventType.ACTIVATED.equals(e.getEventType())) { + final String desc = e.getDescription(); + if (desc != null) { + ElementJavadoc doc = currentDocumentation.resolveLink(desc); + if (doc != null) { + setData(doc, false); + } + } + } + } + } + + private class DocPaneAction extends AbstractAction { + private static final long serialVersionUID = -5754757066129335109L; + + private int action; + + private DocPaneAction(int action) { + this.action = action; + } + + public void actionPerformed(java.awt.event.ActionEvent actionEvent) { + switch (action) { + case ACTION_JAVADOC_BACK: + backHistory(); + break; + case ACTION_JAVADOC_FORWARD: + forwardHistory(); + break; + case ACTION_JAVADOC_OPEN_IN_BROWSER: + openInExternalBrowser(); + break; + case ACTION_JAVADOC_OPEN_SOURCE: + goToSource(); + break; + } + } + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/EventsModel.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/EventsModel.java new file mode 100644 index 000000000000..6b30d5d6f1a5 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/EventsModel.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.Element; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.SourceUtils; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelException; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +public final class EventsModel extends DefaultTreeModel implements + JavaHierarchyModel +{ + + private static final long serialVersionUID = -4924076156788647582L; + + private static final Logger LOG = Logger.getLogger( + EventsModel.class.getName()); + + public EventsModel( List fields , + CompilationController controller ,MetadataModel model ) + { + super( null ); + myModel = model; + myHandles = new ArrayList>( fields.size()); + for (VariableElement field : fields) { + ElementHandle handle = ElementHandle.create( field ); + myHandles.add( handle ); + } + + update( fields , controller ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.JavaHierarchyModel#fireTreeNodesChanged() + */ + @Override + public void fireTreeNodesChanged() { + super.fireTreeNodesChanged(this, getPathToRoot((TreeNode)getRoot()), + null, null); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.JavaHierarchyModel#update() + */ + @Override + public void update() { + updateHandles( myHandles ); + } + + private void update( List vars , + CompilationController controller) + { + DefaultMutableTreeNode root = new DefaultMutableTreeNode(); + + for (VariableElement var : vars) { + FileObject fileObject = SourceUtils.getFile(ElementHandle + .create(var), controller.getClasspathInfo()); + InjectableTreeNode node = + new InjectableTreeNode(fileObject, var, + (DeclaredType)controller.getElementUtilities(). + enclosingTypeElement(var).asType(), false,controller); + root.add( node ); + } + setRoot(root); + } + + private void updateHandles( final List> handles ) { + try { + getModel().runReadAction( + new MetadataModelAction() { + + public Void run( WebBeansModel model ) { + List list = + new ArrayList(handles.size()); + for (ElementHandle handle : + handles) + { + VariableElement var = handle.resolve( + model.getCompilationController()); + if ( var != null ){ + list.add( var ); + } + } + update( list , model.getCompilationController()); + return null; + } + }); + + return; + } + catch (MetadataModelException e) { + LOG.log(Level.WARNING, e.getMessage(), e); + } + catch (IOException e) { + LOG.log(Level.WARNING, e.getMessage(), e); + } + } + + private MetadataModel getModel(){ + return myModel; + } + + private MetadataModel myModel; + private List> myHandles; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/EventsPanel.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/EventsPanel.java new file mode 100644 index 000000000000..3d6ce4acd3ae --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/EventsPanel.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.swing.JLabel; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.openide.awt.Mnemonics; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class EventsPanel extends BindingsPanel { + + private static final long serialVersionUID = -965978443984786734L; + + public EventsPanel( Object[] subject, + MetadataModel metaModel , WebBeansModel model , + EventsModel uiModel ) + { + super(subject, metaModel, model, uiModel); + initLabels(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.InjectablesPanel#getSubjectElement(org.netbeans.api.java.source.ElementHandle, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel) + */ + @Override + protected Element getSubjectElement( Element context, WebBeansModel model ) + { + ExecutableElement method = (ExecutableElement)context; + return model.getObserverParameter( method ); + } + + private void initLabels() { + JLabel typeLabel = getSubjectElementLabel(); + Mnemonics.setLocalizedText(typeLabel,NbBundle.getMessage( + ObserversPanel.class, "LBL_ObservedEventType") ); // NOI18N + typeLabel.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSN_ObservedEventType")); // NOI18N + typeLabel.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSD_ObservedEventType")); // NOI18N + + JLabel qualifiersLabel= getSubjectBindingsLabel(); + Mnemonics.setLocalizedText(qualifiersLabel,NbBundle.getMessage( + ObserversPanel.class, "LBL_ObservedEventQualifiers") ); // NOI18N + qualifiersLabel.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSN_ObservedEventQualifiers")); // NOI18N + qualifiersLabel.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSD_ObservedEventQualifiers")); // NOI18N + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/HTMLDocView.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/HTMLDocView.java new file mode 100644 index 000000000000..3a53d9fc3d3b --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/HTMLDocView.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.awt.Color; +import java.awt.Insets; +import java.awt.Rectangle; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; + +import javax.swing.JEditorPane; +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.EditorKit; +import javax.swing.text.html.HTMLEditorKit; + +/** + * HTML documentation view. + * Javadoc content is displayed in JEditorPane pane using HTMLEditorKit. + * + * Copy of HTMLDocView in java.naviation. + * + * @author ads + */ +class HTMLDocView extends JEditorPane { + + private static final long serialVersionUID = 6743108080998604204L; + + private HTMLEditorKit htmlKit; + + /** Creates a new instance of HTMLJavaDocView */ + public HTMLDocView(Color bgColor) { + setEditable(false); + setFocusable(true); + setBackground(bgColor); + setMargin(new Insets(0,3,3,3)); + } + + /** Sets the javadoc content as HTML document */ + public void setContent(final String content, final String reference) { + SwingUtilities.invokeLater(new Runnable(){ + public void run(){ + Reader in = new StringReader(""+content+"");//NOI18N + try{ + Document doc = getDocument(); + doc.remove(0, doc.getLength()); + getEditorKit().read(in, getDocument(), 0); //!!! still too expensive to be called from AWT + setCaretPosition(0); + if (reference != null) { + SwingUtilities.invokeLater(new Runnable(){ + public void run(){ + scrollToReference(reference); + } + }); + } else { + scrollRectToVisible(new Rectangle(0,0,0,0)); + } + }catch(IOException ioe){ + ioe.printStackTrace(); + }catch(BadLocationException ble){ + ble.printStackTrace(); + } + } + }); + } + + protected EditorKit createDefaultEditorKit() { + // it is extremelly slow to init it + if (htmlKit == null){ + htmlKit= new HTMLEditorKit (); + setEditorKit(htmlKit); + + // override the Swing default CSS to make the HTMLEditorKit use the + // same font as the rest of the UI. + + // XXX the style sheet is shared by all HTMLEditorKits. We must + // detect if it has been tweaked by ourselves or someone else + // (template description for example) and avoid doing the same + // thing again + + if (htmlKit.getStyleSheet().getStyleSheets() != null) + return htmlKit; + + javax.swing.text.html.StyleSheet css = new javax.swing.text.html.StyleSheet(); + java.awt.Font f = getFont(); + css.addRule(new StringBuffer("body { font-size: ").append(f.getSize()) // NOI18N + .append("; font-family: ").append(f.getName()).append("; }").toString()); // NOI18N + css.addStyleSheet(htmlKit.getStyleSheet()); + htmlKit.setStyleSheet(css); + } + return htmlKit; + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/InjectableTreeNode.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/InjectableTreeNode.java new file mode 100644 index 000000000000..6a7df31b34f3 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/InjectableTreeNode.java @@ -0,0 +1,217 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.io.IOException; +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.Modifier; +import javax.lang.model.type.DeclaredType; +import javax.swing.Icon; +import javax.swing.tree.DefaultMutableTreeNode; + +import org.netbeans.api.java.source.ClasspathInfo; +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.JavaSource; +import org.netbeans.api.java.source.Task; +import org.netbeans.api.java.source.JavaSource.Phase; +import org.netbeans.api.java.source.ui.ElementIcons; +import org.netbeans.api.java.source.ui.ElementJavadoc; +import org.netbeans.api.java.source.ui.ElementOpen; +import org.openide.awt.StatusDisplayer; +import org.openide.filesystems.FileObject; +import org.openide.util.Exceptions; +import org.openide.util.NbBundle; + +class InjectableTreeNode extends DefaultMutableTreeNode + implements JavaElement +{ + private static final long serialVersionUID = -6398205566811265151L; + + InjectableTreeNode(FileObject fileObject, + T element, DeclaredType parentType, boolean disabled , + CompilationInfo compilationInfo) + { + myFileObject = fileObject; + myElementHandle = ElementHandle.create(element); + myElementKind = element.getKind(); + myModifiers = element.getModifiers(); + myCpInfo = compilationInfo.getClasspathInfo(); + isDisabled = disabled; + + setName(element.getSimpleName().toString()); + setIcon(ElementIcons.getElementIcon(element.getKind(), element.getModifiers())); + setLabel(Utils.format(element, parentType, compilationInfo)); + setFQNLabel(Utils.format(element, parentType, compilationInfo , false, true)); + setToolTip(Utils.format(element, parentType, compilationInfo, true, + WebBeansNavigationOptions.isShowFQN())); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.JavaElement#isDisabled() + */ + @Override + public boolean isDisabled() { + return isDisabled; + } + + @Override + public FileObject getFileObject() { + return myFileObject; + } + + @Override + public String getName() { + return myName; + } + + @Override + public Set getModifiers() { + return myModifiers; + } + + @Override + public ElementKind getElementKind() { + return myElementKind; + } + + protected void setName(String name) { + myName = name; + } + + @Override + public String getLabel() { + return myLabel; + } + + @Override + public String getFQNLabel() { + return myFQNlabel; + } + + @Override + public String getTooltip() { + return myTooltip; + } + + @Override + public Icon getIcon() { + return myIcon; + } + + protected void setIcon(Icon icon) { + myIcon = icon; + } + + protected void setLabel(String label) { + myLabel = label; + } + + protected void setFQNLabel(String FQNlabel) { + myFQNlabel = FQNlabel; + } + + protected void setToolTip(String tooltip) { + myTooltip = tooltip; + } + + public ElementJavadoc getJavaDoc() { + if (myJavaDoc == null) { + if (myFileObject == null) { + // Probably no source file - so cannot get Javadoc + return null; + } + + JavaSource javaSource = JavaSource.forFileObject(myFileObject); + + if (javaSource != null) { + try { + javaSource.runUserActionTask(new Task() { + public void run( + CompilationController compilationController) + throws Exception { + compilationController.toPhase(Phase.ELEMENTS_RESOLVED); + Element element = myElementHandle.resolve(compilationController); + setJavaDoc(ElementJavadoc.create(compilationController, element)); + } + }, true); + } catch (IOException ioe) { + Exceptions.printStackTrace(ioe); + } + } + } + return myJavaDoc; + } + + protected void setJavaDoc(ElementJavadoc javaDoc) { + myJavaDoc = javaDoc; + } + + @Override + public ElementHandle getElementHandle() { + return myElementHandle; + } + + @Override + public void gotoElement() { + openElementHandle(); + } + + @Override + public String toString() { + return (WebBeansNavigationOptions.isShowFQN()? getFQNLabel() : getLabel()); + } + + protected void openElementHandle() { + if (myFileObject == null) { + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage(InjectablesModel.class, + "MSG_CouldNotOpenElement", getFQNLabel())); // NOI18N + return; + } + + if (myElementHandle == null) { + return; + } + + if (!ElementOpen.open(myCpInfo, myElementHandle)) { + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage(InjectablesModel.class, + "MSG_CouldNotOpenElement", getFQNLabel()));// NOI18N + } + } + + private FileObject myFileObject; + private ElementHandle myElementHandle; + private ElementKind myElementKind; + private Set myModifiers; + private String myName = ""; + private String myLabel = ""; + private String myFQNlabel = ""; + private String myTooltip ; + private Icon myIcon ; + private ElementJavadoc myJavaDoc; + private final ClasspathInfo myCpInfo; + private boolean isDisabled; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/InjectablesModel.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/InjectablesModel.java new file mode 100644 index 000000000000..b319908fb967 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/InjectablesModel.java @@ -0,0 +1,418 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.SourceUtils; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelException; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.openide.filesystems.FileObject; + +/** + * @author ads + */ +public final class InjectablesModel extends DefaultTreeModel + implements JavaHierarchyModel +{ + + private static final long serialVersionUID = -6845959436250662000L; + + private static final Logger LOG = Logger.getLogger( + InjectablesModel.class.getName()); + + static Element[] EMPTY_ELEMENTS_ARRAY = new Element[0]; + + public InjectablesModel(DependencyInjectionResult result, + CompilationController controller ,MetadataModel model ) + { + super(null); + + myModel = model; + if ( result.getKind() == DependencyInjectionResult.ResultKind.DEFINITION_ERROR || + !( result instanceof DependencyInjectionResult.ApplicableResult)) + { + myTypeHandles= Collections.emptyList(); + myProductionHandles = Collections.emptyMap(); + return; + } + + DependencyInjectionResult.ApplicableResult applicableResult = + (DependencyInjectionResult.ApplicableResult) result; + Set typeElements = applicableResult.getTypeElements(); + + myProductionHandles = new HashMap, + ElementHandle>(); + + myDisabledBeans = new HashSet>(); + Set disabled = new HashSet(); + + myTypeHandles = new ArrayList>(typeElements.size()); + for (TypeElement el : typeElements) { + ElementHandle handle = ElementHandle.create(el); + myTypeHandles.add(handle); + if ( applicableResult.isDisabled(el)){ + myDisabledBeans.add( handle ); + disabled.add( el ); + } + } + + Set productions = applicableResult.getProductions(); + Map productionMap = new HashMap(); + for (Element production : productions) { + ElementHandle handleKey = ElementHandle.create( production ); + TypeElement clazz = controller.getElementUtilities(). + enclosingTypeElement(production); + myProductionHandles.put(handleKey, ElementHandle.create( clazz ) ); + productionMap.put( production, clazz ); + if ( applicableResult.isDisabled(production)){ + myDisabledBeans.add( handleKey ); + disabled.add( production ); + } + } + + update( typeElements, productionMap, disabled , controller); + } + + @Override + public void update() { + update( myTypeHandles , myProductionHandles ); + } + + @Override + public void fireTreeNodesChanged() { + super.fireTreeNodesChanged(this, getPathToRoot((TreeNode)getRoot()), + null, null); + } + + private void update( final List> typeHandles , + final Map,ElementHandle> + productions ) + { + try { + getModel().runReadAction( + new MetadataModelAction() { + + @Override + public Void run( WebBeansModel model ) { + Set disabled = new HashSet(); + List typesList = fillTypes(typeHandles, + model, disabled); + + Map productionsMap = + fillProductions( productions, model , disabled); + + update(typesList, productionsMap , disabled , model + .getCompilationController()); + return null; + } + }); + + return; + } + catch (MetadataModelException e) { + LOG.log(Level.WARNING, e.getMessage(), e); + } + catch (IOException e) { + LOG.log(Level.WARNING, e.getMessage(), e); + } + } + + private Map fillProductions( + Map, ElementHandle> productions, + WebBeansModel model, Set disabled ) + { + Map result; + if ( productions == null || productions.size() == 0){ + result = Collections.emptyMap(); + } + else { + result = new HashMap(); + for(Entry,ElementHandle> + entry : productions.entrySet() ) + { + ElementHandle handle = entry.getKey(); + Element element = handle.resolve(model.getCompilationController()); + if (element != null) { + if (myDisabledBeans.contains(handle)) { + disabled.add(element); + } + result.put(element, entry.getValue().resolve( + model.getCompilationController())); + } + else { + LOG.warning(handle.toString() + + " cannot be resolved using: " // NOI18N + + model.getCompilationController() + .getClasspathInfo()); + } + } + } + return result; + } + + private List fillTypes(final List> + typeHandles, WebBeansModel model, Set disabled ) + { + List typesList; + if (typeHandles != null && typeHandles.size() != 0) + { + typesList = new ArrayList( + typeHandles.size()); + + for (ElementHandle + typeHandle : typeHandles) + { + TypeElement element = typeHandle + .resolve(model + .getCompilationController()); + if (element != null) { + typesList.add(element); + if ( myDisabledBeans.contains( typeHandle)){ + disabled.add( element); + } + } + else { + LOG.warning(typeHandle.toString() + + " cannot be resolved using: " // NOI18N + + model.getCompilationController() + .getClasspathInfo()); + } + } + } + else { + typesList = Collections.emptyList(); + } + return typesList; + } + + private void update(final Collection typeElements, + final Map productions, final + Set disabledBeans, + CompilationController controller) + { + if (typeElements.size()==0 && productions.size() == 0 ) { + return; + } + + DefaultMutableTreeNode root = new DefaultMutableTreeNode(); + Map> elementMap= + new LinkedHashMap>(); + + for (TypeElement element : typeElements) { + FileObject fileObject = SourceUtils.getFile(ElementHandle + .create(element), controller.getClasspathInfo()); + // Type declaration + TypeTreeNode node = new TypeTreeNode(fileObject, + element, disabledBeans.contains( element), + controller); + insertTreeNode(elementMap, element, node, root, + disabledBeans.contains(element), controller); + } + + for (Entry entry : productions.entrySet()){ + Element element = entry.getKey(); + FileObject fileObject = SourceUtils.getFile(ElementHandle + .create(element), controller.getClasspathInfo()); + if ( element instanceof ExecutableElement ){ + // Method definition + MethodTreeNode node = new MethodTreeNode(fileObject, + (ExecutableElement)element, + (DeclaredType)entry.getValue().asType(), + disabledBeans.contains( element), controller); + insertTreeNode( elementMap , (ExecutableElement)element , + node , root , controller); + } + else { + // Should be produces field. + InjectableTreeNode node = + new InjectableTreeNode(fileObject, element, + (DeclaredType)entry.getValue().asType(), + disabledBeans.contains(element),controller); + insertTreeNode( elementMap , node , root ); + } + } + + setRoot(root); + } + + private void insertTreeNode( Map> elementMap,TypeElement element , + TypeTreeNode node, DefaultMutableTreeNode root , boolean isDisabled, + CompilationController controller) + { + TypeTreeNode parent = null; + + for( Entry> entry : + elementMap.entrySet()) + { + Element key = entry.getKey(); + if ( !( key instanceof TypeElement )){ + continue; + } + TypeTreeNode injectableNode = (TypeTreeNode)entry.getValue(); + TypeElement typeElement = (TypeElement)key; + if ( controller.getTypes().isAssignable( element.asType(), + typeElement.asType())) + { + if ( parent == null ){ + parent = injectableNode; + } + else if ( parent.isAssignableFrom(typeElement, controller)){ + parent = injectableNode; + } + } + } + + DefaultMutableTreeNode parentNode = parent; + + if ( parentNode == null ){ + parentNode = root; + } + Enumeration children = parentNode.children(); + List movedChildren = new LinkedList(); + while (children.hasMoreElements()) { + TypeTreeNode childNode = (TypeTreeNode) children.nextElement(); + if (childNode.isAssignable(element, controller)) + { + movedChildren.add(childNode); + } + } + + for (TypeTreeNode typeTreeNode : movedChildren) { + parentNode.remove(typeTreeNode); + node.add(typeTreeNode); + } + parentNode.add(node); + elementMap.put(element, node); + } + + static void insertTreeNode( Map> elementMap, + ExecutableElement element , MethodTreeNode node, + DefaultMutableTreeNode root , CompilationController controller) + { + MethodTreeNode parent = null; + + List overriddenMethods = new ArrayList(); + ExecutableElement overriddenMethod = element; + while ( true ){ + overriddenMethod = + controller.getElementUtilities().getOverriddenMethod(overriddenMethod); + if ( overriddenMethod == null ){ + break; + } + overriddenMethods.add( overriddenMethod ); + } + if ( overriddenMethods.size() > 0 ) + { + for (Entry> entry : + elementMap.entrySet()) + { + Element key = entry.getKey(); + if (!(key instanceof ExecutableElement)) { + continue; + } + MethodTreeNode injectableNode = (MethodTreeNode) entry + .getValue(); + ExecutableElement method = (ExecutableElement) key; + + int index = overriddenMethods.indexOf( method); + if ( index != -1 ) { + if (parent == null) { + parent = injectableNode; + } + else if (parent.isOverridden( index, overriddenMethods, + controller)) + { + parent = injectableNode; + } + } + } + } + + DefaultMutableTreeNode parentNode = parent; + + if ( parentNode == null ){ + parentNode = root; + } + Enumeration children = parentNode.children(); + List movedChildren = new LinkedList(); + while (children.hasMoreElements()) { + Object child = children.nextElement(); + if (child instanceof MethodTreeNode) { + MethodTreeNode childNode = (MethodTreeNode)child; + if (childNode.overridesMethod(element, controller)) { + movedChildren.add(childNode); + } + } + } + + for (MethodTreeNode methodNode : movedChildren) { + parentNode.remove(methodNode); + node.add(methodNode); + } + parentNode.add(node); + elementMap.put(element, node); + } + + private void insertTreeNode( Map> elementMap, + InjectableTreeNode node, DefaultMutableTreeNode root ) + { + root.add( node ); + } + + private MetadataModel getModel(){ + return myModel; + } + + private List> myTypeHandles; + private Map,ElementHandle> myProductionHandles; + private Set> myDisabledBeans; + private MetadataModel myModel; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/InjectablesPopup.form b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/InjectablesPopup.form new file mode 100644 index 000000000000..acd1cfbf09b0 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/InjectablesPopup.form @@ -0,0 +1,94 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/InjectablesPopup.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/InjectablesPopup.java new file mode 100644 index 000000000000..58e6385658c2 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/InjectablesPopup.java @@ -0,0 +1,212 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.awt.Component; +import java.awt.Cursor; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.swing.DefaultListCellRenderer; +import javax.swing.DefaultListModel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.ListModel; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.ui.ElementIcons; +import org.netbeans.api.java.source.ui.ElementOpen; + +/** + * @author ads + * + */ +public class InjectablesPopup extends JPanel implements FocusListener { + + private static final long serialVersionUID = -6156872540472708548L; + + /** Creates new form DeclarationPopup */ + public InjectablesPopup(String title, List> handles, + CompilationController controller ) + { + myTitle = title; + myHandles = handles; + myController = controller; + + initComponents(); + + jList1.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + + addFocusListener(this); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + java.awt.GridBagConstraints gridBagConstraints; + + jLabel1 = new javax.swing.JLabel(); + jScrollPane1 = new javax.swing.JScrollPane(); + jList1 = new javax.swing.JList(); + + setFocusCycleRoot(true); + setLayout(new java.awt.GridBagLayout()); + + jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + jLabel1.setText(myTitle + ); + jLabel1.setFocusable(false); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + add(jLabel1, gridBagConstraints); + + jList1.setModel(createListModel()); + jList1.setCellRenderer(new RendererImpl( myController )); + jList1.setSelectedIndex(0); + jList1.setVisibleRowCount(myHandles.size() + ); + jList1.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyPressed(java.awt.event.KeyEvent evt) { + jList1KeyPressed(evt); + } + }); + jList1.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + jList1MouseClicked(evt); + } + }); + jScrollPane1.setViewportView(jList1); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.weighty = 1.0; + add(jScrollPane1, gridBagConstraints); + }// //GEN-END:initComponents + + private void jList1MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jList1MouseClicked + if (evt.getButton() == MouseEvent.BUTTON1 && evt.getClickCount() == 1) { + openSelected(); + } + }//GEN-LAST:event_jList1MouseClicked + + private void jList1KeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jList1KeyPressed + if (evt.getKeyCode() == KeyEvent.VK_ENTER && evt.getModifiers() == 0) { + openSelected(); + } + }//GEN-LAST:event_jList1KeyPressed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel jLabel1; + private javax.swing.JList jList1; + private javax.swing.JScrollPane jScrollPane1; + // End of variables declaration//GEN-END:variables + + private void openSelected() { + ElementHandle handle = (ElementHandle) jList1.getSelectedValue(); + + ElementOpen.open(myController.getClasspathInfo(), handle); + + PopupUtil.hidePopup(); + } + + private ListModel createListModel() { + DefaultListModel> dlm = new DefaultListModel<>(); + + for (ElementHandle el: myHandles) { + dlm.addElement(el); + } + + return dlm; + } + + private static class RendererImpl extends DefaultListCellRenderer { + + private static final long serialVersionUID = -15584610894401459L; + + RendererImpl(CompilationController controller){ + myController = controller; + } + + @Override + public Component getListCellRendererComponent( + JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) { + Component c = super.getListCellRendererComponent(list, value, index, + isSelected, cellHasFocus); + + if (value instanceof ElementHandle) { + ElementHandle handle = (ElementHandle)value; + Element resolve = handle.resolve( myController); + if ( resolve!= null) { + DeclaredType parent = null; + if ( resolve instanceof VariableElement || + resolve instanceof ExecutableElement ) + { + TypeElement enclosingTypeElement = + myController.getElementUtilities(). + enclosingTypeElement(resolve); + parent = (DeclaredType)enclosingTypeElement.asType(); + } + setIcon(ElementIcons.getElementIcon(resolve.getKind(), + resolve.getModifiers())); + setText(Utils.format(resolve, parent , myController)); + } + } + + return c; + } + + private CompilationController myController; + } + + @Override + public void focusGained(FocusEvent arg0) { + jList1.requestFocus(); + jList1.requestFocusInWindow(); + } + + @Override + public void focusLost(FocusEvent arg0) { + } + + private String myTitle; + private List> myHandles; + private CompilationController myController; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/InterceptorsModel.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/InterceptorsModel.java new file mode 100644 index 000000000000..1d3f871b7679 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/InterceptorsModel.java @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.TypeElement; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.SourceUtils; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelException; +import org.netbeans.modules.jakarta.web.beans.api.model.InterceptorsResult; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +public final class InterceptorsModel extends DefaultTreeModel + implements JavaHierarchyModel +{ + + private static final long serialVersionUID = 8135037731227112414L; + + private static final Logger LOG = Logger.getLogger( + InterceptorsModel.class.getName()); + + public InterceptorsModel( InterceptorsResult result , + CompilationController controller ,MetadataModel model ) + { + super( null ); + myModel = model; + List interceptors = result.getAllInterceptors(); + myHandles = new ArrayList>( interceptors.size()); + myDisabledInterceptors = new HashSet>(); + Set disabled = new HashSet(); + for (TypeElement interceptor : interceptors) { + ElementHandle handle = ElementHandle.create( interceptor ); + myHandles.add( handle ); + if ( result.isDisabled( interceptor )){ + myDisabledInterceptors.add( handle ); + disabled.add( interceptor ); + } + } + + update( interceptors , disabled , controller ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.JavaHierarchyModel#fireTreeNodesChanged() + */ + @Override + public void fireTreeNodesChanged() { + super.fireTreeNodesChanged(this, getPathToRoot((TreeNode)getRoot()), + null, null); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.JavaHierarchyModel#update() + */ + @Override + public void update() { + updateHandles( myHandles , myDisabledInterceptors); + } + + private void update( List types , Set disabled, + CompilationController controller) + { + DefaultMutableTreeNode root = new DefaultMutableTreeNode(); + + for (TypeElement type : types) { + FileObject fileObject = SourceUtils.getFile(ElementHandle + .create(type), controller.getClasspathInfo()); + TypeTreeNode node = new TypeTreeNode(fileObject, type, + disabled.contains(type ),controller); + root.add( node ); + } + setRoot(root); + } + + private void updateHandles( final List> handles , + final Set> disabled ) + { + try { + getModel().runReadAction( + new MetadataModelAction() { + + @Override + public Void run( WebBeansModel model ) { + List list = + new ArrayList(handles.size()); + Set set = new HashSet(); + for (ElementHandle handle : + handles) + { + TypeElement type = handle.resolve( + model.getCompilationController()); + if ( type != null ){ + list.add( type ); + } + if ( disabled.contains( handle )){ + set.add( type ); + } + } + update( list , set, model.getCompilationController()); + return null; + } + }); + + return; + } + catch (MetadataModelException e) { + LOG.log(Level.WARNING, e.getMessage(), e); + } + catch (IOException e) { + LOG.log(Level.WARNING, e.getMessage(), e); + } + } + + private MetadataModel getModel(){ + return myModel; + } + + private MetadataModel myModel; + private List> myHandles; + private Set> myDisabledInterceptors; +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/InterceptorsPanel.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/InterceptorsPanel.java new file mode 100644 index 000000000000..8f9140dbe6e7 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/InterceptorsPanel.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.util.Collection; +import java.util.List; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.swing.JLabel; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.jakarta.web.beans.api.model.CdiException; +import org.netbeans.modules.jakarta.web.beans.api.model.Result; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.openide.awt.Mnemonics; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class InterceptorsPanel extends BindingsPanel { + + private static final long serialVersionUID = -3849331046190789438L; + + public InterceptorsPanel( Object[] subject, + MetadataModel metaModel, WebBeansModel model, + JavaHierarchyModel treeModel, Result result ) + { + super(subject, metaModel, model, treeModel, result); + initLabels(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.BindingsPanel#setContextElement(javax.lang.model.element.Element, org.netbeans.api.java.source.CompilationController) + */ + @Override + protected void setContextElement( Element context, + CompilationController controller ) + { + if ( context instanceof ExecutableElement ){ + ExecutableElement method = (ExecutableElement) context; + getShortElementName().append( context.getSimpleName().toString()); + appendMethodParams(getShortElementName(), method); + + TypeElement enclosingType = controller.getElementUtilities(). + enclosingTypeElement( context ); + String typeFqn = enclosingType.getQualifiedName().toString(); + getFqnElementName().append( typeFqn ); + getFqnElementName().append('.'); + getFqnElementName().append( context.getSimpleName().toString() ); + appendMethodParams(getFqnElementName(), method); + } + else if ( context instanceof TypeElement ){ + TypeElement type = (TypeElement) context; + getShortElementName().append( type.getSimpleName().toString() ); + getFqnElementName().append( type.getQualifiedName().toString() ); + } + } + + @Override + protected void initBindings( WebBeansModel model, Element element){ + Collection interceptorBindings = model.getInterceptorBindings(element); + + StringBuilder fqnBuilder = new StringBuilder(); + StringBuilder builder = new StringBuilder(); + + for (AnnotationMirror annotationMirror : interceptorBindings) { + appendAnnotationMirror(annotationMirror, fqnBuilder, true ); + appendAnnotationMirror(annotationMirror, builder, false ); + } + if ( fqnBuilder.length() >0 ){ + setFqnBindings( fqnBuilder.substring(0 , fqnBuilder.length() -2 )); + setShortBindings( builder.substring(0 , builder.length() -2 )); + } + else { + setFqnBindings(""); + setShortBindings(""); + } + if ( showFqns() ) { + getInitialBindingsComponent().setText( getFqnBindings() ); + } + else { + getInitialBindingsComponent().setText( getShortBindings() ); + } + } + + @Override + protected void doShowSelectedCDI(ElementHandle elementHandle, + WebBeansModel model ) throws CdiException + { + Element element = elementHandle.resolve( + model.getCompilationController()); + if ( element == null ){ + getSelectedBindingsComponent().setText(""); + } + else { + element = getSelectedQualifiedElement( element, model); + Collection interceptorBindings = + model.getInterceptorBindings(element); + StringBuilder builder = new StringBuilder(); + + for (AnnotationMirror annotationMirror : interceptorBindings) { + appendAnnotationMirror(annotationMirror, builder, showFqns() ); + } + String bindingsString = ""; + if ( builder.length() >0 ){ + bindingsString = builder.substring(0 , + builder.length() -2 ); + } + getSelectedBindingsComponent().setText( bindingsString); + setStereotypes(model, element); + } + } + + private void appendMethodParams(StringBuilder builder, ExecutableElement method){ + builder.append('('); + List parameters = method.getParameters(); + int i=0; + for (VariableElement variableElement : parameters) { + String param = variableElement.getSimpleName().toString(); + builder.append( param ); + if ( i < parameters.size() -1 ){ + builder.append(", "); + } + i++; + } + builder.append(')'); + } + + private void initLabels() { + JLabel elementLabel = getSubjectElementLabel(); + Mnemonics.setLocalizedText(elementLabel,NbBundle.getMessage( + ObserversPanel.class, "LBL_InterceptedElement") ); // NOI18N + elementLabel.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSN_InterceptedElement")); // NOI18N + elementLabel.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSD_InterceptedElement")); // NOI18N + + JLabel iBindingsLabel= getSubjectBindingsLabel(); + Mnemonics.setLocalizedText(iBindingsLabel,NbBundle.getMessage( + ObserversPanel.class, "LBL_InterceptorBindings") ); // NOI18N + iBindingsLabel.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSN_InterceptorBindings")); // NOI18N + iBindingsLabel.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSD_InterceptorBindings")); // NOI18N + + JLabel selectedIBindgings = getSelectedBindingsLabel(); + Mnemonics.setLocalizedText(selectedIBindgings,NbBundle.getMessage( + ObserversPanel.class, "LBL_SelectedInterceptorBindings") ); // NOI18N + selectedIBindgings.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSN_SelectedInterceptorBindings")); // NOI18N + selectedIBindgings.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSD_SelectedInterceptorBindings")); // NOI18N + + JLabel selectedStereotypes = getStereotypesLabel(); + Mnemonics.setLocalizedText(selectedStereotypes,NbBundle.getMessage( + ObserversPanel.class, "LBL_IStereotypes") ); // NOI18N + selectedStereotypes.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSN_IStereotypes")); // NOI18N + selectedStereotypes.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSD_IStereotypes")); // NOI18N + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/JavaElement.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/JavaElement.java new file mode 100644 index 000000000000..9e777c6e3803 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/JavaElement.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.util.Set; + +import org.netbeans.api.java.source.ElementHandle; +import org.openide.filesystems.FileObject; + +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.Modifier; +import javax.swing.Icon; +import org.netbeans.api.java.source.ui.ElementJavadoc; + +/** + * The interface representing Java elements in hierarchy and members pop up windows. + * + * Copy of JavaElement at java.navigation + * + * @author ads + */ +public interface JavaElement { + String getName(); + Set getModifiers(); + ElementKind getElementKind(); + String getLabel(); + String getFQNLabel(); + String getTooltip(); + Icon getIcon(); + boolean isDisabled(); + ElementJavadoc getJavaDoc(); + void gotoElement(); + FileObject getFileObject(); + ElementHandle getElementHandle(); +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/JavaHierarchyModel.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/JavaHierarchyModel.java new file mode 100644 index 000000000000..e218a70183a5 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/JavaHierarchyModel.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation; + +import javax.swing.tree.TreeModel; + + +/** + * @author ads + * + */ +interface JavaHierarchyModel extends TreeModel { + + void fireTreeNodesChanged(); + + void update(); + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/JavaTreeCellRenderer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/JavaTreeCellRenderer.java new file mode 100644 index 000000000000..1a6915582cee --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/JavaTreeCellRenderer.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.awt.Component; +import javax.swing.JLabel; +import javax.swing.JTree; +import javax.swing.tree.DefaultTreeCellRenderer; + +/** + * + * Copy of JavaTreeCellRenderer at java.navigation. + * + * @author ads + */ +public final class JavaTreeCellRenderer extends DefaultTreeCellRenderer { + private static final long serialVersionUID = 8126878473944648830L; + + public Component getTreeCellRendererComponent(JTree tree, Object value, + boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { + JLabel label = (JLabel) super.getTreeCellRendererComponent(tree, value, + sel, expanded, leaf, row, hasFocus); + + if (!sel) { + setBackgroundNonSelectionColor(tree.getBackground()); + } + + if (value instanceof JavaElement) { + JavaElement javaElement = (JavaElement) value; + label.setIcon(javaElement.getIcon()); + label.setToolTipText(javaElement.getTooltip()); + label.setEnabled( !javaElement.isDisabled() ); + } + + return label; + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/MethodTreeNode.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/MethodTreeNode.java new file mode 100644 index 000000000000..42cb1c3aca56 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/MethodTreeNode.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.util.List; + +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.type.DeclaredType; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.CompilationInfo; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +class MethodTreeNode extends InjectableTreeNode { + + private static final long serialVersionUID = -137177182006814794L; + + MethodTreeNode( FileObject fileObject, ExecutableElement element, + DeclaredType parentType, boolean disabled , + CompilationInfo compilationInfo ) + { + super(fileObject, element, parentType , disabled, compilationInfo); + } + + boolean isOverridden( int index, + List overriddenMethods, + CompilationController controller ) + { + ExecutableElement exec = getElementHandle().resolve(controller); + if ( exec == null ){ + return true; + } + int execIndex = overriddenMethods.indexOf( exec ); + if ( execIndex == -1){ + return true; + } + return index < execIndex ; + } + + boolean overridesMethod( ExecutableElement element, + CompilationController controller ) + { + ExecutableElement exec = getElementHandle().resolve(controller); + if ( exec == null ){ + return false; + } + ExecutableElement overriddenMethod = exec; + while ( true ){ + overriddenMethod = + controller.getElementUtilities().getOverriddenMethod(overriddenMethod); + if ( overriddenMethod == null ){ + break; + } + if ( overriddenMethod.equals( element )){ + return true; + } + } + return false; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/NoBorderToolBar.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/NoBorderToolBar.java new file mode 100644 index 000000000000..d17e734a96c7 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/NoBorderToolBar.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.awt.Graphics; +import javax.swing.JToolBar; + +/** + * ToolBar that doesn't paint any border. + * + * Copy of NoBorderToolBar at java.navigation + * + * @author ads + */ +public class NoBorderToolBar extends JToolBar { + + private static final long serialVersionUID = 2388606453287832422L; + + /** Creates a new instance of NoBorderToolbar */ + public NoBorderToolBar() { + } + + /** Creates a new instance of NoBorderToolbar + * @param layout + */ + public NoBorderToolBar( int layout ) { + super( layout ); + } + + @Override + protected void paintComponent(Graphics g) { + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/ObserversModel.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/ObserversModel.java new file mode 100644 index 000000000000..b4836a35e182 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/ObserversModel.java @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.type.DeclaredType; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.SourceUtils; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelException; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +public final class ObserversModel extends DefaultTreeModel implements + JavaHierarchyModel +{ + + private static final long serialVersionUID = -7252090049644279891L; + + private static final Logger LOG = Logger.getLogger( + ObserversModel.class.getName()); + + public ObserversModel( List methods , + CompilationController controller ,MetadataModel model ) + { + super( null ); + myModel = model; + myHandles = new ArrayList>( methods.size()); + for (ExecutableElement method : methods) { + ElementHandle handle = ElementHandle.create( method ); + myHandles.add( handle ); + } + + update( methods , controller ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.JavaHierarchyModel#fireTreeNodesChanged() + */ + @Override + public void fireTreeNodesChanged() { + super.fireTreeNodesChanged(this, getPathToRoot((TreeNode)getRoot()), + null, null); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.JavaHierarchyModel#update() + */ + @Override + public void update() { + updateHandles( myHandles ); + } + + private void updateHandles( final List> handles ) { + try { + getModel().runReadAction( + new MetadataModelAction() { + + public Void run( WebBeansModel model ) { + List list = + new ArrayList(handles.size()); + for (ElementHandle handle : + handles) + { + ExecutableElement method = handle.resolve( + model.getCompilationController()); + if ( method != null ){ + list.add( method ); + } + } + update( list , model.getCompilationController()); + return null; + } + }); + + return; + } + catch (MetadataModelException e) { + LOG.log(Level.WARNING, e.getMessage(), e); + } + catch (IOException e) { + LOG.log(Level.WARNING, e.getMessage(), e); + } + } + + private void update( List methods , + CompilationController controller) + { + DefaultMutableTreeNode root = new DefaultMutableTreeNode(); + + Map> methodsMap= + new LinkedHashMap>(); + + for (ExecutableElement method : methods) { + FileObject fileObject = SourceUtils.getFile(ElementHandle + .create(method), controller.getClasspathInfo()); + MethodTreeNode node = new MethodTreeNode(fileObject, + method, (DeclaredType)controller.getElementUtilities(). + enclosingTypeElement(method).asType(), + false, controller); + insertTreeNode( methodsMap , method , node , root , controller); + + } + setRoot(root); + } + + private void insertTreeNode( + Map> methods, + ExecutableElement method, MethodTreeNode node, + DefaultMutableTreeNode root, CompilationController controller ) + { + InjectablesModel.insertTreeNode(methods, method, node, root, controller); + } + + private MetadataModel getModel(){ + return myModel; + } + + private MetadataModel myModel; + private List> myHandles; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/ObserversPanel.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/ObserversPanel.java new file mode 100644 index 000000000000..7c2237d34f2f --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/ObserversPanel.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; +import javax.swing.JLabel; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.openide.awt.Mnemonics; +import org.openide.util.NbBundle; + + + +/** + * @author ads + * + */ +public class ObserversPanel extends BindingsPanel { + + private static final long serialVersionUID = -5038408349629504998L; + + static final String OBSERVES_ANNOTATION = + "jakarta.enterprise.event.Observes"; // NOI18N + + + public ObserversPanel( Object[] subject, + MetadataModel metaModel , WebBeansModel model , + ObserversModel uiModel ) + { + super(subject, metaModel, model , uiModel ); + initLabels(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.InjectablesPanel#setInjectableType(javax.lang.model.type.TypeMirror, org.netbeans.api.java.source.CompilationController) + */ + @Override + protected void setContextElement( Element context, + CompilationController controller ) + { + TypeMirror typeMirror = context.asType(); + TypeMirror parameterType = ((DeclaredType)typeMirror).getTypeArguments().get( 0 ); + super.setContextType(parameterType, controller); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.InjectablesPanel#getQualifiedElement(javax.lang.model.element.Element, org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel) + */ + @Override + protected Element getSelectedQualifiedElement( Element context , + WebBeansModel model) + { + if ( context.getKind() == ElementKind.METHOD){ + return model.getObserverParameter((ExecutableElement)context ); + } + return context; + } + + private void initLabels() { + JLabel typeLabel = getSubjectElementLabel(); + Mnemonics.setLocalizedText(typeLabel,NbBundle.getMessage( + ObserversPanel.class, "LBL_EventType") ); // NOI18N + typeLabel.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSN_EventType")); // NOI18N + typeLabel.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSD_EventType")); // NOI18N + + JLabel qualifiersLabel= getSubjectBindingsLabel(); + Mnemonics.setLocalizedText(qualifiersLabel,NbBundle.getMessage( + ObserversPanel.class, "LBL_EventQualifiers") ); // NOI18N + qualifiersLabel.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSN_EventQualifiers")); // NOI18N + qualifiersLabel.getAccessibleContext().setAccessibleName(NbBundle.getMessage( + ObserversPanel.class, "ACSD_EventQualifiers")); // NOI18N + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/PopupUtil.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/PopupUtil.java new file mode 100644 index 000000000000..9241d885052c --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/PopupUtil.java @@ -0,0 +1,239 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.jakarta.web.beans.navigation; +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.Container; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.event.AWTEventListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.WindowEvent; +import java.awt.event.WindowStateListener; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; +import javax.swing.text.Document; +import javax.swing.text.JTextComponent; + +import org.netbeans.api.editor.EditorRegistry; +import org.openide.windows.WindowManager; + +/** + * Based on PopupUtil from csl.api + * + * @author ads + */ +public final class PopupUtil { + + private static final String CLOSE_KEY = "CloseKey"; //NOI18N + private static final Action CLOSE_ACTION = new CloseAction(); + private static final KeyStroke ESC_KEY_STROKE = KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0 ); + + private static final String POPUP_NAME = "popupComponent"; //NOI18N + private static JDialog popupWindow; + private static HideAWTListener hideListener = new HideAWTListener(); + + // Singleton + private PopupUtil() { + } + + public static boolean isPopupShowing() { + return popupWindow != null; + } + + public static void showPopup( JComponent content, String title, int x, int y) { + if (popupWindow != null ) { + return; // Content already showing + } + + Toolkit.getDefaultToolkit().addAWTEventListener(hideListener, AWTEvent.MOUSE_EVENT_MASK); + + // NOT using PopupFactory + // 1. on linux, creates mediumweight popup taht doesn't refresh behind visible glasspane + // 2. on mac, needs an owner frame otherwise hiding tooltip also hides the popup. (linux requires no owner frame to force heavyweight) + // 3. the created window is not focusable window + + popupWindow = new JDialog( getMainWindow() ); + popupWindow.setName( POPUP_NAME ); + popupWindow.setUndecorated(true); + popupWindow.getRootPane().getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ).put( ESC_KEY_STROKE, CLOSE_KEY ); + popupWindow.getRootPane().getActionMap().put( CLOSE_KEY, CLOSE_ACTION ); + + //set a11y + String a11yName = content.getAccessibleContext().getAccessibleName(); + if(a11yName != null && !a11yName.equals("")) + popupWindow.getAccessibleContext().setAccessibleName(a11yName); + String a11yDesc = content.getAccessibleContext().getAccessibleDescription(); + if(a11yDesc != null && !a11yDesc.equals("")) + popupWindow.getAccessibleContext().setAccessibleDescription(a11yDesc); + + popupWindow.getContentPane().add(content); + + WindowManager.getDefault().getMainWindow().addWindowStateListener(hideListener); + WindowManager.getDefault().getMainWindow().addComponentListener(hideListener); + resizePopup(); + + if (x != (-1)) { + Point p = fitToScreen( x, y, 0 ); + popupWindow.setLocation(p.x, p.y); + + } + + popupWindow.setVisible( true ); + content.requestFocus(); + content.requestFocusInWindow(); + } + + public static void hidePopup() { + if (popupWindow != null) { +// popupWindow.getContentPane().removeAll(); + Toolkit.getDefaultToolkit().removeAWTEventListener(hideListener); + + popupWindow.setVisible( false ); + popupWindow.dispose(); + } + WindowManager.getDefault().getMainWindow().removeWindowStateListener(hideListener); + WindowManager.getDefault().getMainWindow().removeComponentListener(hideListener); + popupWindow = null; + } + + public static JTextComponent findEditor(Document doc) { + JTextComponent comp = EditorRegistry.lastFocusedComponent(); + if (comp.getDocument() == doc) { + return comp; + } + List componentList = EditorRegistry.componentList(); + for (JTextComponent component : componentList) { + if (comp.getDocument() == doc) { + return comp; + } + } + + return null; + } + + + private static void resizePopup() { + popupWindow.pack(); + Point point = new Point(0,0); + SwingUtilities.convertPointToScreen(point, getMainWindow()); + popupWindow.setLocation( point.x + (getMainWindow().getWidth() - popupWindow.getWidth()) / 2, + point.y + (getMainWindow().getHeight() - popupWindow.getHeight()) / 3); + } + + private static final int X_INSET = 10; + + private static Point fitToScreen( int x, int y, int altHeight ) { + + Rectangle screen = org.openide.util.Utilities.getUsableScreenBounds(); + + Point p = new Point( x, y ); + + // Adjust the x postition if necessary + if ( ( p.x + popupWindow.getWidth() ) > ( screen.x + screen.width - X_INSET ) ) { + p.x = screen.x + screen.width - X_INSET - popupWindow.getWidth(); + } + + // Adjust the y position if necessary + if ( ( p.y + popupWindow.getHeight() ) > ( screen.y + screen.height - X_INSET ) ) { + p.y = p.y - popupWindow.getHeight() - altHeight; + } + + return p; + } + + + private static Frame getMainWindow() { + return WindowManager.getDefault().getMainWindow(); + } + + // Innerclasses ------------------------------------------------------------ + + private static class HideAWTListener extends ComponentAdapter implements AWTEventListener, WindowStateListener { + + public void eventDispatched(java.awt.AWTEvent aWTEvent) { + if (aWTEvent instanceof MouseEvent) { + MouseEvent mv = (MouseEvent)aWTEvent; + if (mv.getID() == MouseEvent.MOUSE_CLICKED && mv.getClickCount() > 0) { + //#118828 + if (! (aWTEvent.getSource() instanceof Component)) { + hidePopup(); + return; + } + + Component comp = (Component)aWTEvent.getSource(); + Container par = SwingUtilities.getAncestorNamed(POPUP_NAME, comp); //NOI18N + if ( par == null ) { + hidePopup(); + } + } + } + } + + public void windowStateChanged(WindowEvent windowEvent) { + if (popupWindow != null ) { + int oldState = windowEvent.getOldState(); + int newState = windowEvent.getNewState(); + + if (((oldState & Frame.ICONIFIED) == 0) && + ((newState & Frame.ICONIFIED) == Frame.ICONIFIED)) { + hidePopup(); + } + } + + } + + public void componentResized(ComponentEvent evt) { + if (popupWindow != null) { + resizePopup(); + } + } + + public void componentMoved(ComponentEvent evt) { + if (popupWindow!= null) { + resizePopup(); + } + } + + } + + private static class CloseAction extends AbstractAction { + + private static final long serialVersionUID = -6991538204946001510L; + + public void actionPerformed(java.awt.event.ActionEvent e) { + hidePopup(); + } + + + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/ResizablePopup.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/ResizablePopup.java new file mode 100644 index 000000000000..d6b62723f06e --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/ResizablePopup.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.awt.Window; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; + +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.RootPaneContainer; + +import org.openide.windows.WindowManager; + +/** + * Copied from ResizablePopup at java.navigation. + * + * @author ads + */ +public final class ResizablePopup { + static final String HELP_COOKIE = "help"; // NOI18N + + private static final WindowListener windowListener = new WindowAdapter() { + + public void windowClosing(WindowEvent windowEvent) { + cleanup(windowEvent.getWindow()); + } + + private void cleanup(Window window) { + window.setVisible(false); + if (window instanceof RootPaneContainer) { + ((RootPaneContainer) window).setContentPane(new JPanel()); + } + window.removeWindowListener(this); + window.dispose(); + } + + /*private boolean aboutToShowHelp(Window window) { + if (window instanceof RootPaneContainer) { + JComponent rootPane = ((RootPaneContainer) window).getRootPane(); + if (Boolean.TRUE.equals(rootPane.getClientProperty(HELP_COOKIE))) { + rootPane.putClientProperty(HELP_COOKIE, null); + return true; + } + } + return false; + }*/ + }; + + public static JDialog getDialog() { + JDialog dialog = new JDialog(WindowManager.getDefault().getMainWindow(), + "", false) + { + private static final long serialVersionUID = -2488334519927160789L; + + public void setVisible(boolean visible) { + boolean wasVisible = isVisible(); + if (wasVisible && !visible) { + WebBeansNavigationOptions.setLastBounds(getBounds()); + } + super.setVisible(visible); + } + }; + //dialog.setUndecorated(true); + dialog.setBounds(WebBeansNavigationOptions.getLastBounds()); + dialog.addWindowListener(windowListener); + dialog.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE); + return dialog; + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/TypeTreeNode.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/TypeTreeNode.java new file mode 100644 index 000000000000..e6a60d75a598 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/TypeTreeNode.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation; + +import javax.lang.model.element.TypeElement; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.CompilationInfo; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +class TypeTreeNode extends InjectableTreeNode { + + private static final long serialVersionUID = 5945151445570825042L; + + TypeTreeNode(FileObject fileObject, TypeElement typeElement, boolean disabled, + CompilationInfo compilationInfo) + { + super(fileObject, typeElement, null, disabled, compilationInfo); + } + + boolean isAssignableFrom( TypeElement element , + CompilationController controller) + { + TypeElement typeElement = getElementHandle().resolve(controller); + if ( typeElement ==null ){ + return true; + } + return controller.getTypes().isAssignable( element.asType(), + typeElement.asType()); + } + + boolean isAssignable( TypeElement element , CompilationController controller ){ + TypeElement typeElement = getElementHandle().resolve(controller); + if ( typeElement ==null ){ + return false; + } + return controller.getTypes().isAssignable( typeElement.asType(), + element.asType()); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/Utils.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/Utils.java new file mode 100644 index 000000000000..90db53813aad --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/Utils.java @@ -0,0 +1,589 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.TypeParameterElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; +import javax.lang.model.type.WildcardType; +import javax.swing.JTree; +import javax.swing.SwingUtilities; + +import org.netbeans.api.java.source.CompilationInfo; + + +/** + * Based on Utils class from java.navigation + * @author ads + * + */ +final class Utils { + + static void firstRow(JTree tree) { + int rowCount = tree.getRowCount(); + if (rowCount > 0) { + tree.setSelectionRow(0); + scrollTreeToSelectedRow(tree); + } + } + + static void scrollTreeToSelectedRow(final JTree tree) { + final int selectedRow = tree.getLeadSelectionRow(); + if (selectedRow >=0) { + SwingUtilities.invokeLater( + new Runnable() { + public void run() { + tree.scrollRectToVisible(tree.getRowBounds(selectedRow)); + } + } + ); + } + } + + static void previousRow(JTree tree) { + int rowCount = tree.getRowCount(); + if (rowCount > 0) { + int selectedRow = tree.getSelectionModel().getMinSelectionRow(); + if (selectedRow == -1) { + selectedRow = (rowCount -1); + } else { + selectedRow--; + if (selectedRow < 0) { + selectedRow = (rowCount -1); + } + } + tree.setSelectionRow(selectedRow); + scrollTreeToSelectedRow(tree); + } + } + + static void nextRow(JTree tree) { + int rowCount = tree.getRowCount(); + if (rowCount > 0) { + int selectedRow = tree.getSelectionModel().getMinSelectionRow(); + if (selectedRow == -1) { + selectedRow = 0; + tree.setSelectionRow(selectedRow); + } else { + selectedRow++; + } + tree.setSelectionRow(selectedRow % rowCount); + scrollTreeToSelectedRow(tree); + } + } + + static void lastRow(JTree tree) { + int rowCount = tree.getRowCount(); + if (rowCount > 0) { + tree.setSelectionRow(rowCount - 1); + scrollTreeToSelectedRow(tree); + } + } + + static boolean patternMatch(JavaElement javaToolsJavaElement, String pattern, + String patternLowerCase) + { + + if (pattern == null) { + return true; + } + + String patternRegexpString = pattern; + + if (pattern.trim().length() == 0) { + patternRegexpString = pattern + ".*"; + } else { + patternRegexpString = pattern. + replaceAll(Pattern.quote("*"), Matcher.quoteReplacement(".*")). + replaceAll(Pattern.quote("?"), Matcher.quoteReplacement(".")) + + (pattern.endsWith("$") ? "" : ".*"); + } + + String name = javaToolsJavaElement.getName(); + + try { + Pattern compiledPattern = Pattern.compile(patternRegexpString, + WebBeansNavigationOptions.isCaseSensitive() ? 0 + : Pattern.CASE_INSENSITIVE); + Matcher m = compiledPattern.matcher(name); + + return m.matches(); + } catch (PatternSyntaxException pse) { + if (WebBeansNavigationOptions.isCaseSensitive()) { + return name.startsWith(pattern); + } + + return name.toLowerCase().startsWith(patternLowerCase); + } + } + + static String format(Element element, DeclaredType parent , + CompilationInfo compilationInfo) + { + return format(element, parent, compilationInfo, false, false); + } + + static String format(Element element, DeclaredType parent , + CompilationInfo compilationInfo, boolean forSignature, boolean FQNs) + { + StringBuilder stringBuilder = new StringBuilder(); + format(element, parent , compilationInfo , stringBuilder, forSignature, FQNs); + + return stringBuilder.toString(); + } + + static void format(Element element, DeclaredType parent , + CompilationInfo compilationInfo , StringBuilder stringBuilder, + boolean forSignature, boolean FQNs) + { + if (element == null) { + return; + } + + Set modifiers = element.getModifiers(); + + switch (element.getKind()) { + case PACKAGE: + break; + case CLASS: + case INTERFACE: + case ENUM: + case ANNOTATION_TYPE: + if (forSignature) { + stringBuilder.append(toString(modifiers)); + if (modifiers.size() > 0) { + if (stringBuilder.length() > 0) { + stringBuilder.append(" "); + } + } + } + + if (forSignature) { + switch (element.getKind()) { + case CLASS: + stringBuilder.append("class "); // NOI18N + break; + case INTERFACE: + stringBuilder.append("interface "); // NOI18N + break; + case ENUM: + stringBuilder.append("enum "); // NOI18N + break; + case ANNOTATION_TYPE: + stringBuilder.append("@interface "); // NOI18N + break; + } + } + + TypeElement typeElement = (TypeElement) element; + stringBuilder.append(FQNs + ? typeElement.getQualifiedName().toString() + : typeElement.getSimpleName().toString()); + + formatTypeParameters(typeElement.getTypeParameters(), + compilationInfo, stringBuilder, FQNs); + + break; + + case CONSTRUCTOR: + break; + + case METHOD: + ExecutableElement methodElement = (ExecutableElement) element; + ExecutableType methodType = (ExecutableType)compilationInfo.getTypes(). + asMemberOf(parent, methodElement); + TypeMirror returnTypeMirror = methodType.getReturnType(); + /*List typeParameters = + methodElement.getTypeParameters();*/ + List typeVars = methodType.getTypeVariables(); + + if (forSignature) { + stringBuilder.append(toString(modifiers)); + + if (modifiers.size() > 0) { + if (stringBuilder.length() > 0) { + stringBuilder.append(" "); + } + } + + /*if ((typeParameters != null) && (typeParameters.size() > 0)) { + formatTypeParameters(typeParameters, compilationInfo, + stringBuilder, FQNs); + if (stringBuilder.length() > 0) { + stringBuilder.append(" "); + } + }*/ + if ((typeVars != null) && (typeVars.size() > 0)) { + formatTypeMirrors(typeVars, stringBuilder, FQNs); + if (stringBuilder.length() > 0) { + stringBuilder.append(" "); + } + } + + formatTypeMirror(returnTypeMirror, stringBuilder, FQNs); + } + + if (stringBuilder.length() > 0) { + stringBuilder.append(" "); + } + + stringBuilder.append(methodElement.getSimpleName().toString()); + stringBuilder.append("("); + List parameterTypes = methodType.getParameterTypes(); + /*formatVariableElements(methodElement.getParameters(), + methodElement.isVarArgs(), compilationInfo, stringBuilder, FQNs);*/ + formatTypeMirrors(parameterTypes, stringBuilder, FQNs); + if (methodElement.isVarArgs()) { + stringBuilder.append("..."); + } + stringBuilder.append(")"); + + List thrownTypesMirrorsByMethod = methodElement.getThrownTypes(); + if (!thrownTypesMirrorsByMethod.isEmpty()) { + stringBuilder.append(" throws "); // NOI18N + formatTypeMirrors(thrownTypesMirrorsByMethod, stringBuilder, FQNs); + } + + if (forSignature) { + AnnotationValue annotationValue = methodElement.getDefaultValue(); + if (annotationValue != null) { + Object annotationValueValue = annotationValue.getValue(); + if (annotationValueValue != null) { + stringBuilder.append(" default "); // NOI18N + if (annotationValueValue instanceof String) { + stringBuilder.append("\""); + } else if (annotationValueValue instanceof Character) { + stringBuilder.append("\'"); + } + stringBuilder.append(String.valueOf(annotationValueValue)); + if (annotationValueValue instanceof String) { + stringBuilder.append("\""); + } else if (annotationValueValue instanceof Character) { + stringBuilder.append("\'"); + } + } + } + } else { + stringBuilder.append(":"); + + formatTypeMirror(returnTypeMirror, stringBuilder, FQNs); + + /*if ((typeParameters != null) && (typeParameters.size() > 0)) { + stringBuilder.append(":"); + formatTypeParameters(typeParameters, compilationInfo, + stringBuilder, FQNs); + }*/ + if ((typeVars != null) && (typeVars.size() > 0)) { + stringBuilder.append(":"); + formatTypeMirrors(typeVars, stringBuilder, FQNs); + } + + } + + break; + + case TYPE_PARAMETER: + break; + + case FIELD: + VariableElement fieldElement = (VariableElement) element; + TypeMirror fieldType = compilationInfo.getTypes(). + asMemberOf(parent, fieldElement); + if (forSignature) { + stringBuilder.append(toString(modifiers)); + + if (stringBuilder.length() > 0) { + stringBuilder.append(" "); + } + + formatTypeMirror(fieldType, stringBuilder, FQNs); + } + + if (stringBuilder.length() > 0) { + stringBuilder.append(" "); + } + + stringBuilder.append(fieldElement.getSimpleName().toString()); + + if (forSignature) { + Object fieldValue = fieldElement.getConstantValue(); + if (fieldValue != null) { + stringBuilder.append(" = "); + if (fieldValue instanceof String) { + stringBuilder.append("\""); + } else if (fieldValue instanceof Character) { + stringBuilder.append("\'"); + } + stringBuilder.append(String.valueOf(fieldValue)); + if (fieldValue instanceof String) { + stringBuilder.append("\""); + } else if (fieldValue instanceof Character) { + stringBuilder.append("\'"); + } + } + } else { + stringBuilder.append(":"); + + formatTypeMirror(fieldType, stringBuilder, FQNs); + } + + break; + + case ENUM_CONSTANT: + + break; + + case PARAMETER: + case LOCAL_VARIABLE: + break; + } + } + + static String toString(Set modifiers) { + return java.lang.reflect.Modifier.toString(getIntModifiers(modifiers)); + } + + static int getIntModifiers(Set modifiers) { + int intModifiers = 0; + + if (modifiers.contains(Modifier.ABSTRACT)) { + intModifiers |= java.lang.reflect.Modifier.ABSTRACT; + } + + if (modifiers.contains(Modifier.FINAL)) { + intModifiers |= java.lang.reflect.Modifier.FINAL; + } + + if (modifiers.contains(Modifier.NATIVE)) { + intModifiers |= java.lang.reflect.Modifier.NATIVE; + } + + if (modifiers.contains(Modifier.PRIVATE)) { + intModifiers |= java.lang.reflect.Modifier.PRIVATE; + } + + if (modifiers.contains(Modifier.PROTECTED)) { + intModifiers |= java.lang.reflect.Modifier.PROTECTED; + } + + if (modifiers.contains(Modifier.PUBLIC)) { + intModifiers |= java.lang.reflect.Modifier.PUBLIC; + } + + if (modifiers.contains(Modifier.STATIC)) { + intModifiers |= java.lang.reflect.Modifier.STATIC; + } + + if (modifiers.contains(Modifier.STRICTFP)) { + intModifiers |= java.lang.reflect.Modifier.STRICT; + } + + if (modifiers.contains(Modifier.SYNCHRONIZED)) { + intModifiers |= java.lang.reflect.Modifier.SYNCHRONIZED; + } + + if (modifiers.contains(Modifier.TRANSIENT)) { + intModifiers |= java.lang.reflect.Modifier.TRANSIENT; + } + + if (modifiers.contains(Modifier.VOLATILE)) { + intModifiers |= java.lang.reflect.Modifier.VOLATILE; + } + + return intModifiers; + } + + static void formatTypeParameters( + List typeParameters, + CompilationInfo compilationInfo,StringBuilder stringBuilder, + boolean FQNs ) + { + if ((typeParameters == null) || (typeParameters.size() == 0)) { + return; + } + + boolean first = true; + if (typeParameters.size() > 0) { + stringBuilder.append("<"); + first = true; + + for (TypeParameterElement typeParameterElement : typeParameters) { + if (first) { + first = false; + } + else { + stringBuilder.append(", "); + } + + format(typeParameterElement, null, compilationInfo, + stringBuilder, false, FQNs); + } + + stringBuilder.append(">"); + } + } + + static void formatTypeMirrors( List typeMirros, + StringBuilder stringBuilder, boolean FQNs ) + { + if ((typeMirros == null) || (typeMirros.size() == 0)) { + return; + } + + boolean first = true; + + for (TypeMirror typeMirror : typeMirros) { + if (first) { + first = false; + } + else { + stringBuilder.append(", "); + } + + formatTypeMirror(typeMirror, stringBuilder, FQNs); + } + } + + static void formatTypeMirror( TypeMirror typeMirror, + StringBuilder stringBuilder, boolean FQNs ) + { + if (typeMirror == null) { + return; + } + + switch (typeMirror.getKind()) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case LONG: + case NONE: + case NULL: + case SHORT: + case VOID: + stringBuilder.append(typeMirror); + + break; + + case TYPEVAR: + TypeVariable typeVariable = (TypeVariable) typeMirror; + stringBuilder.append(typeVariable.asElement().getSimpleName() + .toString()); + break; + + case WILDCARD: + WildcardType wildcardType = (WildcardType) typeMirror; + stringBuilder.append("?"); + if (wildcardType.getExtendsBound() != null) { + stringBuilder.append(" extends "); // NOI18N + formatTypeMirror(wildcardType.getExtendsBound(), + stringBuilder, FQNs); + } + if (wildcardType.getSuperBound() != null) { + stringBuilder.append(" super "); // NOI18N + formatTypeMirror(wildcardType.getSuperBound(), + stringBuilder, FQNs); + } + + break; + + case DECLARED: + DeclaredType declaredType = (DeclaredType) typeMirror; + Element element = declaredType.asElement(); + if (element instanceof TypeElement) { + stringBuilder.append(FQNs ? ((TypeElement) element) + .getQualifiedName().toString() : element + .getSimpleName().toString()); + } + else { + stringBuilder.append(element.getSimpleName().toString()); + } + List typeArgs = declaredType + .getTypeArguments(); + if (!typeArgs.isEmpty()) { + stringBuilder.append("<"); + formatTypeMirrors(typeArgs, stringBuilder, FQNs); + stringBuilder.append(">"); + } + + break; + + case ARRAY: + + int dims = 0; + + while (typeMirror.getKind() == TypeKind.ARRAY) { + dims++; + typeMirror = ((ArrayType) typeMirror).getComponentType(); + } + + formatTypeMirror(typeMirror, stringBuilder, FQNs); + + for (int i = 0; i < dims; i++) { + stringBuilder.append("[]"); + } + + break; + } + } + + /*static void formatVariableElements( + List variableElements, boolean varArgs, + StringBuilder stringBuilder, boolean FQNs ) + { + if ((variableElements == null) || (variableElements.size() == 0)) { + return; + } + + boolean first = true; + + for (VariableElement variableElement : variableElements) { + if (first) { + first = false; + } + else { + stringBuilder.append(", "); + } + + format(variableElement, stringBuilder, false, FQNs); + } + + if (varArgs) { + stringBuilder.append("..."); + } + }*/ +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/WebBeansNavigationOptions.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/WebBeansNavigationOptions.java new file mode 100644 index 000000000000..9caaaf50d282 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/WebBeansNavigationOptions.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation; + +import java.awt.Dimension; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.util.prefs.Preferences; + +import org.openide.util.NbPreferences; + + +/** + * @author ads + * + */ +final class WebBeansNavigationOptions { + + private static final String PROP_caseSensitive = "caseSensitive"; // NOI18N + private static final String PROP_showFQN = "showFQN"; // NOI18N + private static final String PROP_lastBoundsX = "lastBoundsX"; // NOI18N + private static final String PROP_lastBoundsY = "lastBoundsY"; // NOI18N + private static final String PROP_lastBoundsWidth = "lastBoundsWidth"; // NOI18N + private static final String PROP_lastBoundsHeight = "lastBoundsHeight";// NOI18N + private static final String PROP_hierarchyDividerLocation = + "hierarchyDividerLocation"; // NOI18N + + private static final Preferences getPreferences() { + return NbPreferences.forModule(WebBeansNavigationOptions.class); + } + + static boolean isCaseSensitive() { + return getPreferences().getBoolean(PROP_caseSensitive, myCaseSensitive); + } + + static boolean isShowFQN() { + return getPreferences().getBoolean(PROP_showFQN, myShowFQN); + } + + static void setCaseSensitive( boolean selected ) { + getPreferences().putBoolean(PROP_caseSensitive, myCaseSensitive); + } + + static void setShowFQN( boolean selected ) { + getPreferences().putBoolean(PROP_showFQN, selected); + } + + static void setLastBounds( Rectangle bounds ) { + if (bounds != null) { + getPreferences().putInt(PROP_lastBoundsX, bounds.x); + getPreferences().putInt(PROP_lastBoundsY, bounds.y); + getPreferences().putInt(PROP_lastBoundsWidth, bounds.width); + getPreferences().putInt(PROP_lastBoundsHeight, bounds.height); + } + } + + static int getHierarchyDividerLocation() { + return getPreferences().getInt(PROP_hierarchyDividerLocation, + myHierarchyDividerLocation); + } + + static void setHierarchyDividerLocation(int hierarchyDividerLocation) { + getPreferences().putInt(PROP_hierarchyDividerLocation, + hierarchyDividerLocation); + } + + static Rectangle getLastBounds() { + int x = getPreferences().getInt(PROP_lastBoundsX, myLastBounds.x); + int y = getPreferences().getInt(PROP_lastBoundsY, myLastBounds.y); + int width = getPreferences().getInt(PROP_lastBoundsWidth, myLastBounds.width); + int height = getPreferences().getInt(PROP_lastBoundsHeight, myLastBounds.height); + + return new Rectangle(x, y, width, height); + } + + private static boolean myCaseSensitive = false; + + private static int myHierarchyDividerLocation = 350; + + private static boolean myShowFQN = false; + + private static Rectangle myLastBounds; + + static + { + Dimension dimensions = Toolkit.getDefaultToolkit().getScreenSize(); + myLastBounds = new Rectangle(((dimensions.width / 2) - 410), + ((dimensions.height / 2) - 300), 820, 600); + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/AbstractCdiAction.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/AbstractCdiAction.java new file mode 100644 index 000000000000..8e54775c8c35 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/AbstractCdiAction.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation.actions; + +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.swing.text.JTextComponent; + +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.modules.editor.NbEditorUtilities; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelException; +import org.netbeans.modules.jakarta.web.beans.MetaModelSupport; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +abstract class AbstractCdiAction extends AbstractWebBeansAction { + + private static final long serialVersionUID = -2083083648443423425L; + + AbstractCdiAction( String name ) { + super(name); + } + + /* (non-Javadoc) + * @see org.netbeans.editor.BaseAction#actionPerformed(java.awt.event.ActionEvent, javax.swing.text.JTextComponent) + */ + @Override + public void actionPerformed( ActionEvent event, final JTextComponent component ) { + if ( component == null ){ + Toolkit.getDefaultToolkit().beep(); + return; + } + final FileObject fileObject = NbEditorUtilities.getFileObject( + component.getDocument()); + if ( fileObject == null ){ + Toolkit.getDefaultToolkit().beep(); + return; + } + Project project = FileOwnerQuery.getOwner( fileObject ); + if ( project == null ){ + Toolkit.getDefaultToolkit().beep(); + return; + } + + handleProject( project , event ); + + MetaModelSupport support = new MetaModelSupport(project); + final MetadataModel metaModel = support.getMetaModel(); + if ( metaModel == null ){ + Toolkit.getDefaultToolkit().beep(); + return; + } + + /* + * this list will contain variable element name and TypeElement + * qualified name which contains variable element. + */ + final Object[] context = new Object[3]; + if ( !findContext(component, context) ){ + return; + } + + try { + metaModel.runReadAction( new MetadataModelAction() { + + @Override + public Void run( WebBeansModel model ) throws Exception { + modelAcessAction(model, metaModel, context, component, + fileObject); + return null; + } + }); + } + catch (MetadataModelException e) { + Logger.getLogger( AbstractInjectableAction.class.getName()). + log( Level.INFO, e.getMessage(), e); + } + catch (IOException e) { + Logger.getLogger( AbstractInjectableAction.class.getName()). + log( Level.WARNING, e.getMessage(), e); + } + } + + protected void handleProject( Project project , ActionEvent event ) { + } + + protected abstract boolean findContext(final JTextComponent component , + Object[] context); + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/AbstractInjectableAction.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/AbstractInjectableAction.java new file mode 100644 index 000000000000..8d0abdfbe15b --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/AbstractInjectableAction.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation.actions; + +import javax.swing.text.JTextComponent; + + +/** + * @author ads + * + */ +abstract class AbstractInjectableAction extends AbstractCdiAction { + + private static final long serialVersionUID = 6150283611609922936L; + + AbstractInjectableAction(String name ){ + super( name ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.AbstractCdiAction#findContext(javax.swing.text.JTextComponent, java.lang.Object[]) + */ + @Override + protected boolean findContext( JTextComponent component, Object[] context ) + { + return WebBeansActionHelper.getVariableElementAtDot( component, + context , true ); + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/AbstractWebBeansAction.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/AbstractWebBeansAction.java new file mode 100644 index 000000000000..52dfd80387b3 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/AbstractWebBeansAction.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation.actions; + +import javax.swing.text.JTextComponent; + +import org.netbeans.editor.BaseAction; +import org.netbeans.editor.ext.ExtKit; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.openide.filesystems.FileObject; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +abstract class AbstractWebBeansAction extends BaseAction { + + private static final long serialVersionUID = -6226167569468730445L; + + AbstractWebBeansAction(String name ){ + super( name , 0 ); + + putValue(ACTION_COMMAND_KEY, getActionCommand()); + putValue(SHORT_DESCRIPTION, getValue(NAME)); + putValue(ExtKit.TRIMMED_TEXT,getValue(NAME)); + putValue(POPUP_MENU_TEXT, NbBundle.getMessage( + AbstractWebBeansAction.class, + getPopupMenuKey())); + + putValue("noIconInMenu", Boolean.TRUE); // NOI18N + } + + + /* (non-Javadoc) + * @see javax.swing.AbstractAction#isEnabled() + */ + @Override + public boolean isEnabled() { + return WebBeansActionHelper.isEnabled(); + } + + /* (non-Javadoc) + * @see org.netbeans.editor.BaseAction#asynchonous() + */ + @Override + protected boolean asynchonous() { + return true; + } + + protected abstract void modelAcessAction( WebBeansModel model, + MetadataModel metaModel, + Object[] subject, JTextComponent component , + FileObject fileObject); + + protected abstract String getActionCommand(); + + protected abstract String getPopupMenuKey(); + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/Bundle.properties b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/Bundle.properties new file mode 100644 index 000000000000..b00e8e3c7b84 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/Bundle.properties @@ -0,0 +1,75 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +inspect-cdi-at-caret=CDI +inspect-cdi-at-caret-popup=Inspect CDI +#inspect-observers-at-caret=Ob&servers +#inspect-observers-at-caret-popup=Inspect Observers + +go-to-injactable-at-caret=Injectable +go-to-injactable-at-caret-popup=Go to Injectable + +go-to-decorator-at-caret=Decorator +go-to-decorator-at-caret-popup=Go to Decorator + +#go-to-observer-at-caret=&Observers +#go-to-observer-at-caret-popup=Go to Observers + +#inspect-events-at-caret=E&vents +#inspect-events-at-caret-popup=Inspect Event Declarations + +LBL_ChooseInjectable=Choose element eligible for injection + +LBL_VariableNotFound=Could not find "{0}" element. +LBL_InjectableNotFound=There is no element eligible for injection. +TITLE_Injectables=Ambiguous dependency for "{0}" injection point + +LBL_ElementNotFound=No Java element found on caret position. +LBL_NotVariableElement=Injection point should be a variable element. +LBL_MethodNotFound=Method "{0}" for injection point parameter "{1}" not found. +LBL_NotInjectionPoint=Chosen element is not an injection point. + +LBL_NotEventInjectionPoint=Chosen element is not an event injection point. +LBL_ObserversNotFound=No event observers found for event at caret position. +LBL_ChooseObserver=Choose resolved observer method for given event. +TITLE_Observers=Observers for "{0}" event field. + +LBL_NotObserverContext=Chosen element does not observe any event. +LBL_NotDecorator=No injection context available: chosen type element is declared as \ +as decorator but has no delegate injection point. + +TITLE_Events=Event injection points for "{0}" observer method +TITLE_Interceptors=Interceptors for chosen "{0}" element + +LBL_NoCdiContext=No CDI context available + +TITLE_Decorators=Decorators for chosen "{0}" element + +LBL_NotTypeElement=Chosen element is not type element declaration. +LBL_DecoratorsNotFound=Could not find appropriate decorators. +LBL_EnabledDecoratorsNotFound=Could not find enabled decorators. + +LBL_ChooseDecorator=Choose decorator + +TXT_GlyphActionName=CDI Annotation + +USG_CDI_INSPECT_CDI=Called Inspect CDI editor action via popup menu for project "{0}". +USG_CDI_GO_TO_INJECTABLE=Called Go To Injectable editor action via popup menu for project "{0}". +USG_CDI_GO_TO_DECORATOR=Called Go To Injectable editor action via popup menu for project "{0}". +USG_CDI_INSPECT_CDI_GLYPH=Called Inspect CDI editor action via glyph gutter action for project "{0}". +USG_CDI_GO_TO_INJECTABLE_GLYPH=Called Go To Injectable editor action via glyph gutter action for project "{0}". +USG_CDI_GO_TO_DECORATOR_GLYPH=Called Go To Injectable editor action via glyph gutter action for project "{0}". \ No newline at end of file diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/CdiGlyphAction.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/CdiGlyphAction.java new file mode 100644 index 000000000000..b752ddcc3444 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/CdiGlyphAction.java @@ -0,0 +1,292 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation.actions; + +import java.awt.event.ActionEvent; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.text.Document; +import javax.swing.text.JTextComponent; + +import org.netbeans.editor.AnnotationDesc; +import org.netbeans.editor.Annotations; +import org.netbeans.editor.BaseDocument; +import org.netbeans.editor.ImplementationProvider; +import org.netbeans.editor.Utilities; +import org.netbeans.modules.editor.NbEditorUtilities; +import org.netbeans.modules.jakarta.web.beans.hints.CDIAnnotation; +import org.netbeans.modules.jakarta.web.beans.hints.CDIAnnotation.CDIAnnotaitonType; +import org.netbeans.modules.jakarta.web.beans.hints.EditorAnnotationsHelper; +import org.openide.filesystems.FileObject; +import org.openide.loaders.DataObject; +import org.openide.text.Line; +import org.openide.util.NbBundle; + + + +/** + * @author ads + * + */ +public class CdiGlyphAction extends AbstractAction { + + public CdiGlyphAction(){ + putValue(NAME, NbBundle.getMessage(CdiGlyphAction.class, "TXT_GlyphActionName")); // NOI18N + putValue("supported-annotation-types", new String[] { + "org-netbeans-modules-jakarta-web-beans-annotations-injection-point", + "org-netbeans-modules-jakarta-web-beans-annotations-delegate-point", + "org-netbeans-modules-jakarta-web-beans-annotations-decorated-bean", + "org-netbeans-modules-jakarta-web-beans-annotations-event", + "org-netbeans-modules-jakarta-web-beans-annotations-observer", + "org-netbeans-modules-editor-annotations-intercepted" + }); + + } + + /* (non-Javadoc) + * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) + */ + @Override + public void actionPerformed( ActionEvent event ) { + JTextComponent comp = (JTextComponent) event.getSource(); + if (!performCdiAction(comp)) { + Action actions[] = ImplementationProvider.getDefault(). + getGlyphGutterActions(comp); + + if (actions == null) + return ; + + int nextIndex = 0; + + while (nextIndex < actions.length && actions[nextIndex] != this) { + nextIndex++; + } + + nextIndex++; + + if (actions.length > nextIndex) { + Action action = actions[nextIndex]; + if (action!=null && action.isEnabled()){ + action.actionPerformed(event); + } + } + } + } + + private boolean performCdiAction( final JTextComponent comp ) { + final Document document = comp.getDocument(); + if ( document instanceof BaseDocument ){ + final Object values[] = new Object[2]; + document.render( new Runnable() { + + @Override + public void run() { + int dot = comp.getCaret().getDot(); + Annotations annotations = ((BaseDocument) document).getAnnotations(); + Line line = NbEditorUtilities.getLine(document, dot, false); + if (line == null) { + return ; + } + int lineNumber = line.getLineNumber(); + AnnotationDesc desc = annotations.getActiveAnnotation(lineNumber); + values[0] = lineNumber; + values[1] = desc; + } + }); + + if ( values[0] == null || values[1] == null ){ + return false; + } + int lineNumber = (Integer) values[0]; + AnnotationDesc desc = (AnnotationDesc)values[1]; + String annotationType = desc.getAnnotationType(); + EditorAnnotationsHelper helper = EditorAnnotationsHelper. + getInstance( getFile(comp)); + if ( helper == null ){ + return false; + } + List cdiAnnotations = helper.getAnnotations(); + for (CDIAnnotation cdiAnnotation : cdiAnnotations) { + String cdiAnnotationType = cdiAnnotation.getAnnotationType(); + if ( cdiAnnotationType.equals( annotationType)){ + Line cdiLine = cdiAnnotation.getPart().getLine(); + if ( cdiLine.getLineNumber() == lineNumber ){ + int length = cdiAnnotation.getPart().getLength(); + if ( length == desc.getLength() ){ + doAction( comp , annotationType, cdiAnnotation.getPart(), + (BaseDocument)document); + return true; + } + } + } + } + } + return false; + } + + + private void doAction( JTextComponent comp , String annotationType , + final Line.Part part , BaseDocument doc ) + { + if ( annotationType.equals( CDIAnnotation.CDIAnnotaitonType. + INJECTION_POINT.toString()) || annotationType.equals( + CDIAnnotation.CDIAnnotaitonType.DELEGATE_POINT.toString())) + { + final AnnotationPositionStrategy strategy = + new AnnotationPositionStrategy(part, doc); + GoToInjectableAtCaretAction action = new GoToInjectableAtCaretAction(){ + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.AbstractInjectableAction#findContext(javax.swing.text.JTextComponent, java.lang.Object[]) + */ + @Override + protected boolean findContext( JTextComponent component, + Object[] context ) + { + return WebBeansActionHelper.getVariableElementAtDot( component, + context , true , strategy ); + } + }; + action.actionPerformed(null, comp); + + } + else if ( annotationType.equals( CDIAnnotaitonType.EVENT.toString() )){ + final AnnotationPositionStrategy strategy = + new AnnotationPositionStrategy(part, doc); + InspectCDIAtCaretAction action = new InspectCDIAtCaretAction(){ + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.InspectCDIAtCaretAction#findContext(javax.swing.text.JTextComponent, java.lang.Object[]) + */ + @Override + protected boolean findContext( JTextComponent component, + Object[] subject ) + { + return WebBeansActionHelper.getVariableElementAtDot( component, + subject , false , strategy) || WebBeansActionHelper. + getContextEventInjectionAtDot( component, subject , strategy ); + } + }; + + action.actionPerformed(null, comp); + } + else if ( annotationType.equals( CDIAnnotaitonType.OBSERVER.toString() )){ + final AnnotationPositionStrategy strategy = + new AnnotationPositionStrategy(part, doc); + InspectCDIAtCaretAction action = new InspectCDIAtCaretAction(){ + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.InspectCDIAtCaretAction#findContext(javax.swing.text.JTextComponent, java.lang.Object[]) + */ + @Override + protected boolean findContext( JTextComponent component, + Object[] subject ) + { + return WebBeansActionHelper.getMethodAtDot(component, + subject, strategy ); + } + }; + + action.actionPerformed(null, comp); + } + else if ( annotationType.equals( CDIAnnotaitonType.INTERCEPTED_ELEMENT.toString() )){ + final AnnotationPositionStrategy strategy = + new AnnotationPositionStrategy(part, doc); + InspectCDIAtCaretAction action = new InspectCDIAtCaretAction(){ + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.InspectCDIAtCaretAction#findContext(javax.swing.text.JTextComponent, java.lang.Object[]) + */ + @Override + protected boolean findContext( JTextComponent component, + Object[] subject ) + { + return WebBeansActionHelper.getMethodAtDot(component, + subject, strategy ) || WebBeansActionHelper. + getClassAtDot(component, subject, strategy); + } + }; + + action.actionPerformed(null, comp); + } + else if ( annotationType.equals( CDIAnnotaitonType.DECORATED_BEAN.toString() )){ + final AnnotationPositionStrategy strategy = + new AnnotationPositionStrategy(part, doc); + GoToDecoratorAtCaretAction action = new GoToDecoratorAtCaretAction(){ + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.InspectCDIAtCaretAction#findContext(javax.swing.text.JTextComponent, java.lang.Object[]) + */ + @Override + protected boolean findContext( JTextComponent component, + Object[] subject ) + { + return WebBeansActionHelper. + getClassAtDot(component, subject, strategy); + } + }; + + action.actionPerformed(null, comp); + } + } + + private FileObject getFile(JTextComponent component) { + Document doc = component.getDocument(); + DataObject od = (DataObject) doc.getProperty(Document.StreamDescriptionProperty); + + if (od == null) { + return null; + } + + return od.getPrimaryFile(); + } + + private static class AnnotationPositionStrategy implements + PositionStrategy, Runnable + { + + AnnotationPositionStrategy(Line.Part part, BaseDocument doc ){ + myPart = part; + myDocument = doc; + } + + /* (non-Javadoc) + * @see java.lang.Runnable#run() + */ + @Override + public void run() { + Line line = myPart.getLine(); + int startOffset = Utilities.getRowStartFromLineOffset(myDocument, + line.getLineNumber()); + myOffset = startOffset+myPart.getColumn(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.PositionStrategy#getOffset(javax.swing.text.JTextComponent) + */ + @Override + public int getOffset( JTextComponent component ) { + Document document = component.getDocument(); + document.render( this ); + return myOffset; + } + + private Line.Part myPart; + private BaseDocument myDocument; + private int myOffset; + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/DecoratoresActionStrategy.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/DecoratoresActionStrategy.java new file mode 100644 index 000000000000..421299450f43 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/DecoratoresActionStrategy.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation.actions; + +import java.util.Collection; +import java.util.List; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.swing.SwingUtilities; +import javax.swing.text.JTextComponent; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.jakarta.web.beans.api.model.BeansModel; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.navigation.DecoratorsModel; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +public final class DecoratoresActionStrategy implements ModelActionStrategy { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy#isApplicable(org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy.InspectActionId) + */ + @Override + public boolean isApplicable( InspectActionId id ) { + return id == InspectActionId.CLASS_CONTEXT; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy#isApplicable(org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.lang.Object[]) + */ + @Override + public boolean isApplicable( WebBeansModel model, Object[] context ) { + final Object handle = context[0]; + if ( handle == null ){ + return false; + } + Element element = ((ElementHandle)handle).resolve( + model.getCompilationController()); + if ( element == null ){ + return false; + } + List qualifiers = model.getQualifiers(element, true); + // if class has qualifiers then Class context is considered as decorator context + if ( qualifiers.size() >0 ){ + return true; + } + /* + * If it doesn't have explicit qualifiers then it could have implicit @Default + * qualifier . In the latter case check Interceptor Bindings presence + */ + return model.getInterceptorBindings(element).isEmpty(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy#invokeModelAction(org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, org.netbeans.modules.j2ee.metadata.model.api.MetadataModel, java.lang.Object[], javax.swing.text.JTextComponent, org.openide.filesystems.FileObject) + */ + @Override + public void invokeModelAction( WebBeansModel model, + final MetadataModel metaModel, final Object[] subject, + JTextComponent component, FileObject fileObject ) + { + final Object handle = subject[0]; + Element element = ((ElementHandle)handle).resolve( + model.getCompilationController()); + if ( !( element instanceof TypeElement) ){ + return; + } + TypeElement type = (TypeElement)element; + CompilationController controller = model.getCompilationController(); + Collection decorators = model.getDecorators(type); + BeansModel beansModel = model.getModelImplementation().getBeansModel(); + final DecoratorsModel uiModel = new DecoratorsModel(decorators, + beansModel, controller, metaModel); + final String name = type.getSimpleName().toString(); + if (SwingUtilities.isEventDispatchThread()) { + WebBeansActionHelper.showDecoratorsDialog( metaModel, model, + subject , uiModel , name ); + } + else { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + WebBeansActionHelper.showDecoratorsDialog(metaModel, null , + subject ,uiModel , name ); + } + }); + } + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/EventsActionStartegy.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/EventsActionStartegy.java new file mode 100644 index 000000000000..96130da40900 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/EventsActionStartegy.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation.actions; + +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; +import javax.swing.SwingUtilities; +import javax.swing.text.JTextComponent; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.navigation.EventsModel; +import org.openide.awt.StatusDisplayer; +import org.openide.filesystems.FileObject; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +final class EventsActionStartegy implements ModelActionStrategy { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy#isApplicable(org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy.InspectActionId) + */ + @Override + public boolean isApplicable( InspectActionId id ) { + return id == InspectActionId.METHOD_CONTEXT || id == InspectActionId.INJECTABLES_CONTEXT; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy#isApplicable(org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.lang.Object[]) + */ + @Override + public boolean isApplicable( WebBeansModel model, Object context[] ) { + final Object handle = context[0]; + if ( handle == null ){ + return false; + } + Element element = ((ElementHandle)handle).resolve( + model.getCompilationController()); + ExecutableElement method = null; + if ( element instanceof ExecutableElement ){ + method = (ExecutableElement)element; + } + else { + return false; + } + if ( context[2] == InspectActionId.METHOD_CONTEXT && + model.getObserverParameter( method ) == null ) + { + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage(GoToInjectableAtCaretAction.class, + "LBL_NotObserverContext"), // NOI18N + StatusDisplayer.IMPORTANCE_ERROR_HIGHLIGHT); + return false; + } + return true; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy#invokeModelAction(org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, org.netbeans.modules.j2ee.metadata.model.api.MetadataModel, java.lang.Object[], javax.swing.text.JTextComponent, org.openide.filesystems.FileObject) + */ + @Override + public void invokeModelAction( final WebBeansModel model, + final MetadataModel metaModel, final Object[] subject, + JTextComponent component, FileObject fileObject ) + { + final Object handle = subject[0]; + Element element = ((ElementHandle)handle).resolve( + model.getCompilationController()); + ExecutableElement method = (ExecutableElement)element; + if ( element == null || model.getObserverParameter( method ) == null ){ + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage(EventsActionStartegy.class, + "LBL_NotObserverContext"), // NOI18N + StatusDisplayer.IMPORTANCE_ERROR_HIGHLIGHT); + return; + } + List eventInjectionPoints = model.getEventInjectionPoints( + method , null ); + CompilationController controller = model + .getCompilationController(); + final EventsModel uiModel = new EventsModel(eventInjectionPoints, + controller, metaModel); + final String name = method.getSimpleName().toString(); + if (SwingUtilities.isEventDispatchThread()) { + WebBeansActionHelper.showEventsDialog( metaModel, model, + subject , uiModel , name ); + } + else { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + WebBeansActionHelper.showEventsDialog(metaModel, null , + subject ,uiModel , name ); + } + }); + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/GoToDecoratorAtCaretAction.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/GoToDecoratorAtCaretAction.java new file mode 100644 index 000000000000..9ecaaede9a49 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/GoToDecoratorAtCaretAction.java @@ -0,0 +1,262 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation.actions; + +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; +import javax.swing.text.JTextComponent; + +import org.netbeans.api.java.source.ClasspathInfo; +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.JavaSource; +import org.netbeans.api.java.source.Task; +import org.netbeans.api.java.source.JavaSource.Phase; +import org.netbeans.api.java.source.ui.ElementOpen; +import org.netbeans.api.project.Project; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.jakarta.web.beans.CdiUtil; +import org.netbeans.modules.jakarta.web.beans.api.model.BeansModel; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.api.model.InjectionPointDefinitionError; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.navigation.InjectablesModel; +import org.netbeans.modules.jakarta.web.beans.navigation.InjectablesPopup; +import org.netbeans.modules.jakarta.web.beans.navigation.PopupUtil; +import org.openide.awt.StatusDisplayer; +import org.openide.filesystems.FileObject; +import org.openide.util.Exceptions; +import org.openide.util.NbBundle; + +import com.sun.source.util.TreePath; + + +/** + * @author ads + * + */ +public class GoToDecoratorAtCaretAction extends AbstractCdiAction { + + private static final long serialVersionUID = 6777839777383350958L; + + private static final String GOTO_DECORATOR_AT_CARET = + "go-to-decorator-at-caret"; // NOI18N + + private static final String GOTO_DECORATOR_AT_CARET_POPUP = + "go-to-decorator-at-caret-popup"; // NOI18N + + public GoToDecoratorAtCaretAction( ) { + super(NbBundle.getMessage(GoToInjectableAtCaretAction.class, + GOTO_DECORATOR_AT_CARET)); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.AbstractCdiAction#findContext(javax.swing.text.JTextComponent, java.lang.Object[]) + */ + @Override + protected boolean findContext( final JTextComponent component, + final Object[] context ) + { + JavaSource javaSource = JavaSource.forDocument(component.getDocument()); + if ( javaSource == null ){ + Toolkit.getDefaultToolkit().beep(); + return false; + } + try { + javaSource.runUserActionTask( new Task(){ + @Override + public void run(CompilationController controller) throws Exception { + controller.toPhase( Phase.ELEMENTS_RESOLVED ); + int dot = component.getCaret().getDot(); + TreePath tp = controller.getTreeUtilities().pathFor(dot); + Element contextElement = controller.getTrees().getElement(tp ); + if ( contextElement == null ){ + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage( + WebBeansActionHelper.class, + "LBL_ElementNotFound")); + return; + } + context[0] = contextElement; + } + }, true ); + } + catch (IOException e) { + Logger.getLogger(GoToDecoratorAtCaretAction.class.getName()).log( + Level.INFO, e.getMessage(), e); + } + boolean result = context[0] instanceof TypeElement; + + if ( !result ){ + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage(GoToDecoratorAtCaretAction.class, + "LBL_NotTypeElement"), // NOI18N + StatusDisplayer.IMPORTANCE_ERROR_HIGHLIGHT); + } + else { + context[0] = ElementHandle.create( (TypeElement) context[0]); + } + + return result; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.AbstractWebBeansAction#modelAcessAction(org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, org.netbeans.modules.j2ee.metadata.model.api.MetadataModel, java.lang.Object[], javax.swing.text.JTextComponent, org.openide.filesystems.FileObject) + */ + @Override + protected void modelAcessAction( WebBeansModel model, + final MetadataModel metaModel, Object[] subject, + final JTextComponent component, FileObject fileObject ) + { + Element element = ((ElementHandle)subject[0]).resolve( + model.getCompilationController()); + if (element == null) { + return; + } + Collection decorators = model.getDecorators((TypeElement)element); + if (decorators.size() == 0) { + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage(GoToDecoratorAtCaretAction.class, + "LBL_DecoratorsNotFound"), // NOI18N + StatusDisplayer.IMPORTANCE_ERROR_HIGHLIGHT); + return; + } + + BeansModel beansModel = model.getModelImplementation().getBeansModel(); + final LinkedHashSet enabledDecorators = WebBeansActionHelper. + getEnabledDecorators(decorators, beansModel, null, + model.getCompilationController()); + if (enabledDecorators.size() == 0) { + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage(GoToDecoratorAtCaretAction.class, + "LBL_EnabledDecoratorsNotFound"), // NOI18N + StatusDisplayer.IMPORTANCE_ERROR_HIGHLIGHT); + return; + } + + if (enabledDecorators.size() == 1) { + final ElementHandle handle = ElementHandle + .create(enabledDecorators.iterator().next()); + final ClasspathInfo classpathInfo = model + .getCompilationController().getClasspathInfo(); + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + ElementOpen.open(classpathInfo, handle); + } + }); + } + else { + final CompilationController controller = model + .getCompilationController(); + if (SwingUtilities.isEventDispatchThread()) { + showPopup(enabledDecorators, controller, metaModel, component); + } + else { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + showPopup(enabledDecorators, controller, metaModel, component); + } + }); + } + } + } + + private void showPopup( LinkedHashSet elements , CompilationController + controller, MetadataModel model ,JTextComponent target ) + { + List> handles = new ArrayList< + ElementHandle>(elements.size()); + for (TypeElement element : elements) { + handles.add( ElementHandle.create( element )); + } + StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage( + InjectablesModel.class, "LBL_WaitNode")); + try { + Rectangle rectangle = target.modelToView(target.getCaret().getDot()); + Point point = new Point(rectangle.x, rectangle.y + rectangle.height); + SwingUtilities.convertPointToScreen(point, target); + + String title = NbBundle.getMessage( + GoToInjectableAtCaretAction.class, "LBL_ChooseDecorator"); + PopupUtil.showPopup(new InjectablesPopup(title, handles, controller), title, + point.x, point.y); + + } + catch (BadLocationException ex) { + Exceptions.printStackTrace(ex); + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.AbstractWebBeansAction#getActionCommand() + */ + @Override + protected String getActionCommand() { + return GOTO_DECORATOR_AT_CARET; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.AbstractWebBeansAction#getPopupMenuKey() + */ + @Override + protected String getPopupMenuKey() { + return GOTO_DECORATOR_AT_CARET_POPUP; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.AbstractCdiAction#handleProject(org.netbeans.api.project.Project, java.awt.event.ActionEvent) + */ + @Override + protected void handleProject( Project project , ActionEvent event ) { + String msg = null; + if ( event == null ){ + msg = "USG_CDI_GO_TO_DECORATOR_GLYPH"; // NOI18N + } + else { + msg = "USG_CDI_GO_TO_DECORATOR"; // NOI18N + } + CdiUtil logger = project.getLookup().lookup(CdiUtil.class); + if (logger != null) { + logger.log(msg, + GoToDecoratorAtCaretAction.class, new Object[] { project + .getClass().getName() }); + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/GoToInjectableAtCaretAction.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/GoToInjectableAtCaretAction.java new file mode 100644 index 000000000000..6b7360c2ae6b --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/GoToInjectableAtCaretAction.java @@ -0,0 +1,236 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation.actions; + +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; +import javax.swing.text.JTextComponent; + +import org.netbeans.api.java.source.ClasspathInfo; +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.ui.ElementOpen; +import org.netbeans.api.project.Project; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.jakarta.web.beans.CdiUtil; +import org.netbeans.modules.jakarta.web.beans.api.model.InjectionPointDefinitionError; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.navigation.InjectablesModel; +import org.netbeans.modules.jakarta.web.beans.navigation.InjectablesPopup; +import org.netbeans.modules.jakarta.web.beans.navigation.PopupUtil; +import org.openide.awt.StatusDisplayer; +import org.openide.filesystems.FileObject; +import org.openide.util.Exceptions; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class GoToInjectableAtCaretAction extends AbstractInjectableAction { + + private static final long serialVersionUID = -6998124281864635094L; + + private static final String GOTO_INJACTABLE_AT_CARET = + "go-to-injactable-at-caret"; // NOI18N + + private static final String GOTO_INJACTABLE_AT_CARET_POPUP = + "go-to-injactable-at-caret-popup"; // NOI18N + + public GoToInjectableAtCaretAction() { + super(NbBundle.getMessage(GoToInjectableAtCaretAction.class, + GOTO_INJACTABLE_AT_CARET)); + } + + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.AbstractWebBeansAction#getActionCommand() + */ + @Override + protected String getActionCommand() { + return GOTO_INJACTABLE_AT_CARET; + } + + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.AbstractWebBeansAction#getPopupMenuKey() + */ + @Override + protected String getPopupMenuKey() { + return GOTO_INJACTABLE_AT_CARET_POPUP; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.AbstractWebBeansAction#modelAcessAction(org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, org.netbeans.modules.j2ee.metadata.model.api.MetadataModel, java.lang.Object[], javax.swing.text.JTextComponent, org.openide.filesystems.FileObject) + */ + /** + * Variable element is resolved based on containing type element + * qualified name and simple name of variable itself. + * Model methods are used further for injectable resolution. + */ + @Override + protected void modelAcessAction( WebBeansModel model, + final MetadataModel metaModel, Object[] variable, + final JTextComponent component, FileObject fileObject ) + { + VariableElement var = WebBeansActionHelper.findVariable(model, variable); + if (var == null) { + return; + } + try { + if ( !model.isInjectionPoint(var) ){ + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage(GoToInjectableAtCaretAction.class, + "LBL_NotInjectionPoint"), // NOI18N + StatusDisplayer.IMPORTANCE_ERROR_HIGHLIGHT); + return; + } + } + catch (InjectionPointDefinitionError e) { + StatusDisplayer.getDefault().setStatusText(e.getMessage(), + StatusDisplayer.IMPORTANCE_ERROR_HIGHLIGHT); + } + final DependencyInjectionResult result = model.lookupInjectables(var, null, new AtomicBoolean(false)); + if (result == null) { + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage(GoToInjectableAtCaretAction.class, + "LBL_InjectableNotFound"), // NOI18N + StatusDisplayer.IMPORTANCE_ERROR_HIGHLIGHT); + return; + } + if (result instanceof DependencyInjectionResult.Error) { + StatusDisplayer.getDefault().setStatusText( + ((DependencyInjectionResult.Error) result).getMessage(), + StatusDisplayer.IMPORTANCE_ERROR_HIGHLIGHT); + } + if (result.getKind() == DependencyInjectionResult.ResultKind.DEFINITION_ERROR) { + return; + } + if (result.getKind() == DependencyInjectionResult.ResultKind.INJECTABLE_RESOLVED) { + Element injectable = ((DependencyInjectionResult.InjectableResult) result) + .getElement(); + if(injectable != null) {//may be null for ee specific implemantations, which may not be present on classpath and may not have sources + final ElementHandle handle = ElementHandle + .create(injectable); + final ClasspathInfo classpathInfo = model + .getCompilationController().getClasspathInfo(); + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + ElementOpen.open(classpathInfo, handle); + } + }); + } + } + else if (result.getKind() == DependencyInjectionResult.ResultKind.RESOLUTION_ERROR) { + final CompilationController controller = model + .getCompilationController(); + if (SwingUtilities.isEventDispatchThread()) { + showPopup(result, controller, metaModel, component); + } + else { + SwingUtilities.invokeLater(new Runnable() { + + public void run() { + showPopup(result, controller, metaModel, component); + } + }); + } + } + } + + private void showPopup( DependencyInjectionResult result , CompilationController controller, + MetadataModel model ,JTextComponent target ) + { + if ( !(result instanceof DependencyInjectionResult.ApplicableResult)){ + return; + } + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + if ( typeElements.size() +productions.size() == 0 ){ + return; + } + List> handles = new ArrayList< + ElementHandle>(typeElements.size() +productions.size()); + for (Element element : typeElements) { + if ( !((DependencyInjectionResult.ApplicableResult)result).isDisabled(element)){ + handles.add( ElementHandle.create( element )); + } + } + for (Element element : productions) { + if ( !((DependencyInjectionResult.ApplicableResult)result).isDisabled(element)){ + handles.add( ElementHandle.create( element )); + } + } + if ( handles.size() == 0 ){ + return; + } + StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage( + InjectablesModel.class, "LBL_WaitNode")); // NOI18N + try { + Rectangle rectangle = target.modelToView(target.getCaret().getDot()); + Point point = new Point(rectangle.x, rectangle.y + rectangle.height); + SwingUtilities.convertPointToScreen(point, target); + + String title = NbBundle.getMessage( + GoToInjectableAtCaretAction.class, "LBL_ChooseInjectable"); + PopupUtil.showPopup(new InjectablesPopup(title, handles, controller), title, + point.x, point.y); + + } + catch (BadLocationException ex) { + Exceptions.printStackTrace(ex); + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.AbstractCdiAction#handleProject(org.netbeans.api.project.Project, java.awt.event.ActionEvent) + */ + @Override + protected void handleProject( Project project , ActionEvent event ) { + String msg = null; + if ( event == null ){ + msg = "USG_CDI_GO_TO_INJECTABLE_GLYPH"; // NOI18N + } + else { + msg = "USG_CDI_GO_TO_INJECTABLE"; // NOI18N + } + CdiUtil logger = project.getLookup().lookup(CdiUtil.class); + if (logger != null) { + logger.log(msg, + GoToInjectableAtCaretAction.class, new Object[] { project + .getClass().getName() }); + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/InjectablesActionStrategy.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/InjectablesActionStrategy.java new file mode 100644 index 000000000000..8b1ac2c5bab4 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/InjectablesActionStrategy.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation.actions; + +import java.util.concurrent.atomic.AtomicBoolean; +import javax.lang.model.element.VariableElement; +import javax.swing.SwingUtilities; +import javax.swing.text.JTextComponent; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.jakarta.web.beans.api.model.InjectionPointDefinitionError; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.api.model.Result; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.navigation.InjectablesModel; +import org.openide.awt.StatusDisplayer; +import org.openide.filesystems.FileObject; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public final class InjectablesActionStrategy implements ModelActionStrategy { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy#isApplicable(org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy.InspectActionId) + */ + @Override + public boolean isApplicable( InspectActionId id ) { + return id == InspectActionId.INJECTABLES_CONTEXT ; + } + + @Override + public boolean isApplicable( WebBeansModel model, Object context[] ) { + final VariableElement var = WebBeansActionHelper.findVariable(model, context); + if (var == null) { + return false; + } + try { + if ( model.isEventInjectionPoint(var)){ + return false; + } + if (!model.isInjectionPoint(var)) { + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage(GoToInjectableAtCaretAction.class, + "LBL_NotInjectionPoint"), // NOI18N + StatusDisplayer.IMPORTANCE_ERROR_HIGHLIGHT); + return false; + } + } + catch (InjectionPointDefinitionError e) { + StatusDisplayer.getDefault().setStatusText(e.getMessage(), + StatusDisplayer.IMPORTANCE_ERROR_HIGHLIGHT); + } + return true; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy#invokeModelAction(org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, org.netbeans.modules.j2ee.metadata.model.api.MetadataModel, java.lang.Object[], javax.swing.text.JTextComponent, org.openide.filesystems.FileObject) + */ + @Override + public void invokeModelAction( final WebBeansModel model, + final MetadataModel metaModel, final Object[] subject, + JTextComponent component, FileObject fileObject ) + { + final VariableElement var = WebBeansActionHelper.findVariable(model, + subject); + DependencyInjectionResult result = var== null? null: model.lookupInjectables(var, null, new AtomicBoolean(false)); + if (result == null) { + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage(GoToInjectableAtCaretAction.class, + "LBL_InjectableNotFound"), // NOI18N + StatusDisplayer.IMPORTANCE_ERROR_HIGHLIGHT); + return; + } + if (result instanceof DependencyInjectionResult.Error) { + StatusDisplayer.getDefault().setStatusText( + ((DependencyInjectionResult.Error) result).getMessage(), + StatusDisplayer.IMPORTANCE_ERROR_HIGHLIGHT); + } + if (result.getKind() == DependencyInjectionResult.ResultKind.DEFINITION_ERROR) { + return; + } + CompilationController controller = model + .getCompilationController(); + final InjectablesModel uiModel = new InjectablesModel(result, controller, + metaModel ); + final String name = var.getSimpleName().toString(); + final Result res = (result instanceof Result) ? (Result)result :null; + if (SwingUtilities.isEventDispatchThread()) { + WebBeansActionHelper.showInjectablesDialog(metaModel, model, + subject , uiModel , name , res ); + } + else { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + WebBeansActionHelper.showInjectablesDialog(metaModel, + null , subject ,uiModel , name , res); + } + }); + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/InspectCDIAtCaretAction.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/InspectCDIAtCaretAction.java new file mode 100644 index 000000000000..adf2428f6f59 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/InspectCDIAtCaretAction.java @@ -0,0 +1,198 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation.actions; + +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.swing.text.JTextComponent; + +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.modules.editor.NbEditorUtilities; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelException; +import org.netbeans.modules.jakarta.web.beans.CdiUtil; +import org.netbeans.modules.jakarta.web.beans.MetaModelSupport; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy.InspectActionId; +import org.openide.awt.StatusDisplayer; +import org.openide.filesystems.FileObject; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +public class InspectCDIAtCaretAction extends AbstractWebBeansAction { + + private static final long serialVersionUID = -4505119467924502377L; + + private static final String INSPECT_CDI_AT_CARET = + "inspect-cdi-at-caret"; // NOI18N + + private static final String INSPECT_CDI_AT_CARET_POPUP = + "inspect-cdi-at-caret-popup"; // NOI18N + + public InspectCDIAtCaretAction( ) { + super(NbBundle.getMessage(InspectCDIAtCaretAction.class, + INSPECT_CDI_AT_CARET)); + myStrategies = new ArrayList( 4 ); + /* + * The order is important ! + * EventsActionStartegy should be after InjectablesActionStrategy + * because it cares about several action ids. + */ + myStrategies.add( new ObserversActionStrategy()); + myStrategies.add( new InjectablesActionStrategy()); + myStrategies.add( new DecoratoresActionStrategy()); + myStrategies.add( new InterceptorsActionStrategy()); + myStrategies.add( new EventsActionStartegy()); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.AbstractWebBeansAction#modelAcessAction(org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, org.netbeans.modules.j2ee.metadata.model.api.MetadataModel, java.lang.Object[], javax.swing.text.JTextComponent, org.openide.filesystems.FileObject) + */ + @Override + protected void modelAcessAction( WebBeansModel model, + MetadataModel metaModel, Object[] subject, + JTextComponent component, FileObject fileObject ) + { + InspectActionId id = (InspectActionId) subject[2]; + for( ModelActionStrategy strategy : myStrategies ){ + if ( strategy.isApplicable( id ) && strategy.isApplicable( model , + subject )) + { + strategy.invokeModelAction(model, metaModel, subject, + component, fileObject); + return; + } + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.AbstractWebBeansAction#getActionCommand() + */ + @Override + protected String getActionCommand() { + return INSPECT_CDI_AT_CARET; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.AbstractWebBeansAction#getPopupMenuKey() + */ + @Override + protected String getPopupMenuKey() { + return INSPECT_CDI_AT_CARET_POPUP; + } + + /* (non-Javadoc) + * @see org.netbeans.editor.BaseAction#actionPerformed(java.awt.event.ActionEvent, javax.swing.text.JTextComponent) + */ + @Override + public void actionPerformed( ActionEvent event, final JTextComponent component ) { + if ( component == null ){ + Toolkit.getDefaultToolkit().beep(); + return; + } + final FileObject fileObject = NbEditorUtilities.getFileObject( + component.getDocument()); + if ( fileObject == null ){ + Toolkit.getDefaultToolkit().beep(); + return; + } + Project project = FileOwnerQuery.getOwner( fileObject ); + if ( project == null ){ + Toolkit.getDefaultToolkit().beep(); + return; + } + + String msg = null; + if ( event == null ){ + msg ="USG_CDI_INSPECT_CDI_GLYPH"; // NOI18N + } + else { + msg = "USG_CDI_INSPECT_CDI"; // NOI18N + } + CdiUtil logger = project.getLookup().lookup(CdiUtil.class); + if (logger != null) { + logger.log(msg, + InspectCDIAtCaretAction.class, new Object[] { project + .getClass().getName() }); + } + + MetaModelSupport support = new MetaModelSupport(project); + final MetadataModel metaModel = support.getMetaModel(); + if ( metaModel == null ){ + Toolkit.getDefaultToolkit().beep(); + return; + } + + /* + * this list will contain variable element name and TypeElement + * qualified name which contains variable element. + */ + final Object[] subject = new Object[3]; + if ( !findContext(component, subject)){ + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage( + WebBeansActionHelper.class, "LBL_NoCdiContext")); + return; + } + try { + metaModel.runReadActionWhenReady( new MetadataModelAction() { + + @Override + public Void run( WebBeansModel model ) throws Exception { + modelAcessAction(model, metaModel, subject, component, + fileObject); + return null; + } + }); + } + catch (MetadataModelException e) { + Logger.getLogger( AbstractInjectableAction.class.getName()). + log( Level.INFO, e.getMessage(), e); + } + catch (IOException e) { + Logger.getLogger( AbstractInjectableAction.class.getName()). + log( Level.WARNING, e.getMessage(), e); + } + } + + protected boolean findContext( final JTextComponent component, + final Object[] subject ) + { + return WebBeansActionHelper.getVariableElementAtDot( component, + subject , false ) || WebBeansActionHelper. + getContextEventInjectionAtDot( component, subject ) || + WebBeansActionHelper.getMethodAtDot(component, subject) || + WebBeansActionHelper.getClassAtDot(component, subject); + } + + private List myStrategies; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/InterceptorsActionStrategy.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/InterceptorsActionStrategy.java new file mode 100644 index 000000000000..adfdf3931bee --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/InterceptorsActionStrategy.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation.actions; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.swing.SwingUtilities; +import javax.swing.text.JTextComponent; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.jakarta.web.beans.api.model.InterceptorsResult; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.navigation.InterceptorsModel; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +public final class InterceptorsActionStrategy implements ModelActionStrategy { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy#isApplicable(org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy.InspectActionId) + */ + @Override + public boolean isApplicable( InspectActionId id ) { + return id == InspectActionId.CLASS_CONTEXT|| id == InspectActionId.METHOD_CONTEXT; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy#isApplicable(org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.lang.Object[]) + */ + @Override + public boolean isApplicable( WebBeansModel model, Object[] context ) { + final Object handle = context[0]; + if ( handle == null ){ + return false; + } + Element element = ((ElementHandle)handle).resolve( + model.getCompilationController()); + if (context[2] == InspectActionId.METHOD_CONTEXT) { + if ( !( element instanceof ExecutableElement)) { + return false; + } + return model.getInterceptorBindings(element).size() >0 ; + } + // Now check all interceptor bindings for element + return true; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy#invokeModelAction(org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, org.netbeans.modules.j2ee.metadata.model.api.MetadataModel, java.lang.Object[], javax.swing.text.JTextComponent, org.openide.filesystems.FileObject) + */ + @Override + public void invokeModelAction( WebBeansModel model, + final MetadataModel metaModel, final Object[] subject, + JTextComponent component, FileObject fileObject ) + { + final Object handle = subject[0]; + Element element = ((ElementHandle)handle).resolve( + model.getCompilationController()); + if ( element == null ){ + return; + } + CompilationController controller = model.getCompilationController(); + final InterceptorsResult result = model.getInterceptors(element); + final InterceptorsModel uiModel = new InterceptorsModel( + result , controller, metaModel); + final String name = element.getSimpleName().toString(); + if (SwingUtilities.isEventDispatchThread()) { + WebBeansActionHelper.showInterceptorsDialog( metaModel, model, + subject , uiModel , name, result ); + } + else { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + WebBeansActionHelper.showInterceptorsDialog(metaModel, null , + subject ,uiModel , name , result); + } + }); + } + + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/ModelActionStrategy.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/ModelActionStrategy.java new file mode 100644 index 000000000000..b65f46c49d43 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/ModelActionStrategy.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation.actions; + +import javax.swing.text.JTextComponent; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +public interface ModelActionStrategy { + + public enum InspectActionId { + OBSERVERS_CONTEXT, + METHOD_CONTEXT, + INJECTABLES_CONTEXT, + CLASS_CONTEXT; + } + + boolean isApplicable( InspectActionId id ); + + boolean isApplicable( WebBeansModel model , Object[] context ); + + void invokeModelAction( WebBeansModel model, + MetadataModel metaModel, Object[] subject, + JTextComponent component, FileObject fileObject ); +} + + diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/ObserversActionStrategy.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/ObserversActionStrategy.java new file mode 100644 index 000000000000..e6ba8831d5b4 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/ObserversActionStrategy.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation.actions; + +import java.util.List; + +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; +import javax.swing.SwingUtilities; +import javax.swing.text.JTextComponent; + +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.navigation.ObserversModel; +import org.openide.awt.StatusDisplayer; +import org.openide.filesystems.FileObject; +import org.openide.util.NbBundle; + + +/** + * @author ads + * + */ +final class ObserversActionStrategy implements ModelActionStrategy { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy#isApplicable(org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy.InspectActionId) + */ + @Override + public boolean isApplicable( InspectActionId id ) { + return id == InspectActionId.INJECTABLES_CONTEXT || id == InspectActionId.OBSERVERS_CONTEXT; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy#isApplicable(org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, java.lang.Object[]) + */ + @Override + public boolean isApplicable( WebBeansModel model, Object context[] ) { + final VariableElement var = WebBeansActionHelper.findVariable(model,context); + if (var == null) { + return false; + } + if (context[2] == InspectActionId.OBSERVERS_CONTEXT && + !model.isEventInjectionPoint(var)) + { + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage(GoToInjectableAtCaretAction.class, + "LBL_NotEventInjectionPoint"), // NOI18N + StatusDisplayer.IMPORTANCE_ERROR_HIGHLIGHT); + return false; + } + return model.isEventInjectionPoint(var); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy#invokeModelAction(org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel, org.netbeans.modules.j2ee.metadata.model.api.MetadataModel, java.lang.Object[], javax.swing.text.JTextComponent, org.openide.filesystems.FileObject) + */ + @Override + public void invokeModelAction( final WebBeansModel model, + final MetadataModel metaModel, final Object[] subject, + JTextComponent component, FileObject fileObject ) + { + final VariableElement var = WebBeansActionHelper.findVariable(model, + subject); + final List observers = + var==null?null:model.getObservers( var , null ); + if ( var==null || observers.size() == 0 ){ + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage(GoToInjectableAtCaretAction.class, + "LBL_ObserversNotFound"), // NOI18N + StatusDisplayer.IMPORTANCE_ERROR_HIGHLIGHT); + return; + } + final CompilationController controller = model.getCompilationController(); + final ObserversModel uiModel = new ObserversModel(observers,controller, + metaModel); + final String name = var.getSimpleName().toString(); + if (SwingUtilities.isEventDispatchThread()) { + WebBeansActionHelper.showObserversDialog(observers, metaModel , + model , subject, uiModel ,name ); + } + else { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + WebBeansActionHelper.showObserversDialog(observers, + metaModel, null , subject, uiModel , name ); + } + }); + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/PositionStrategy.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/PositionStrategy.java new file mode 100644 index 000000000000..3ae8b59f55d8 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/PositionStrategy.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation.actions; + +import javax.swing.text.JTextComponent; + + +/** + * @author ads + * + */ +public interface PositionStrategy { + + int getOffset( JTextComponent component ); +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/WebBeansActionHelper.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/WebBeansActionHelper.java new file mode 100644 index 000000000000..cfaa3f5ec6e0 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/navigation/actions/WebBeansActionHelper.java @@ -0,0 +1,778 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.navigation.actions; + + +import java.awt.Toolkit; +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Name; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.util.ElementFilter; +import javax.swing.JDialog; +import javax.swing.text.Document; +import javax.swing.text.JTextComponent; + +import org.netbeans.api.editor.EditorRegistry; +import org.netbeans.api.j2ee.core.Profile; +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.java.lexer.JavaTokenId; +import org.netbeans.api.java.project.JavaProjectConstants; +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.JavaSource; +import org.netbeans.api.java.source.JavaSource.Phase; +import org.netbeans.api.java.source.SourceUtils; +import org.netbeans.api.java.source.Task; +import org.netbeans.api.lexer.Token; +import org.netbeans.api.lexer.TokenHierarchy; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectUtils; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.api.project.ui.OpenProjects; +import org.netbeans.modules.editor.NbEditorUtilities; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.parsing.api.ParserManager; +import org.netbeans.modules.parsing.api.ResultIterator; +import org.netbeans.modules.parsing.api.Source; +import org.netbeans.modules.parsing.api.UserTask; +import org.netbeans.modules.parsing.spi.ParseException; +import org.netbeans.modules.parsing.spi.Parser.Result; +import org.netbeans.modules.web.api.webmodule.WebModule; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.AnnotationUtil; +import org.netbeans.modules.jakarta.web.beans.api.model.BeansModel; +import org.netbeans.modules.jakarta.web.beans.api.model.InterceptorsResult; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.navigation.BindingsPanel; +import org.netbeans.modules.jakarta.web.beans.navigation.DecoratorsModel; +import org.netbeans.modules.jakarta.web.beans.navigation.DecoratorsPanel; +import org.netbeans.modules.jakarta.web.beans.navigation.EventsModel; +import org.netbeans.modules.jakarta.web.beans.navigation.EventsPanel; +import org.netbeans.modules.jakarta.web.beans.navigation.InjectablesModel; +import org.netbeans.modules.jakarta.web.beans.navigation.InterceptorsModel; +import org.netbeans.modules.jakarta.web.beans.navigation.InterceptorsPanel; +import org.netbeans.modules.jakarta.web.beans.navigation.ObserversModel; +import org.netbeans.modules.jakarta.web.beans.navigation.ObserversPanel; +import org.netbeans.modules.jakarta.web.beans.navigation.ResizablePopup; +import org.netbeans.modules.jakarta.web.beans.navigation.actions.ModelActionStrategy.InspectActionId; +import org.openide.awt.StatusDisplayer; +import org.openide.filesystems.FileObject; +import org.openide.util.NbBundle; + +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.MemberSelectTree; +import com.sun.source.tree.MethodInvocationTree; +import com.sun.source.tree.Scope; +import com.sun.source.tree.Tree; +import com.sun.source.tree.Tree.Kind; +import com.sun.source.util.TreePath; + +/** + * @author ads + * + */ +public class WebBeansActionHelper { + + private static final String WAIT_NODE = "LBL_WaitNode"; // NOI18N + + static final String DELEGATE = "jakarta.decorator.Delegate"; // NOI18N + + static final String DECORATOR = "jakarta.decorator.Decorator";// NOI18N + + static final String FIRE = "fire"; // NOI18N + + static final String EVENT_INTERFACE = + "jakarta.enterprise.event.Event"; // NOI18N + + static final String OBSERVES_ANNOTATION = + "jakarta.enterprise.event.Observes"; // NOI18N + + private static final Set USABLE_TOKEN_IDS = + EnumSet.of(JavaTokenId.IDENTIFIER, JavaTokenId.THIS, JavaTokenId.SUPER); + + private static final PositionStrategy CARET_POSITION_STRATEGY = new PositionStrategy() { + + @Override + public int getOffset( JTextComponent component ) { + return component.getCaret().getDot(); + } + }; + + private WebBeansActionHelper(){ + } + + public static boolean isEnabled() { + JTextComponent c = EditorRegistry.lastFocusedComponent(); + if (c == null || !c.isShowing()) + { + return false; + } + if ( OpenProjects.getDefault().getOpenProjects().length == 0 ){ + return false; + } + final FileObject fileObject = NbEditorUtilities.getFileObject(c.getDocument()); + return isEnabled( fileObject ); + /*WebModule webModule = WebModule.getWebModule(fileObject); + if ( webModule == null ){ + return false; + } + Profile profile = webModule.getJ2eeProfile(); + return Profile.JAVA_EE_6_WEB.equals( profile) || + Profile.JAVA_EE_6_FULL.equals( profile );*/ + } + + public static boolean isEnabled(FileObject fileObject){ + if ( fileObject == null ){ + return false; + } + Project project = FileOwnerQuery.getOwner( fileObject ); + if ( project == null ){ + return false; + } + boolean hasJsr330 = hasJsr330(project); + if ( !hasJsr330 ){ + return false; + } + if ( !hasJsr299(project) ){ + return false; + } + return true; + } + + public static boolean hasJsr330( Project project ){ + SourceGroup[] sourceGroups = ProjectUtils.getSources(project). + getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA); + if (sourceGroups.length == 0) { + return false; + } + boolean hasInject = false; + boolean hasQualifier = false; + for (SourceGroup sourceGroup : sourceGroups) { + boolean injectFound = hasResource(sourceGroup, ClassPath.COMPILE, + AnnotationUtil.INJECT_FQN) || + hasResource(sourceGroup, ClassPath.SOURCE, AnnotationUtil.INJECT_FQN); + if ( injectFound ){ + hasInject = true; + } + boolean qualifierFound = hasResource(sourceGroup, ClassPath.COMPILE, + AnnotationUtil.QUALIFIER_FQN) || + hasResource(sourceGroup, ClassPath.SOURCE, AnnotationUtil.QUALIFIER_FQN); + if ( qualifierFound ){ + hasQualifier = true; + } + } + + return hasInject && hasQualifier; + } + + public static boolean hasJsr299( Project project ){ + SourceGroup[] sourceGroups = ProjectUtils.getSources(project). + getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA); + if (sourceGroups.length == 0) { + return false; + } + boolean hasDefault = false; + boolean hasProduces = false; + boolean hasDependent = false; + for (SourceGroup sourceGroup : sourceGroups) { + boolean defaultFound = hasResource(sourceGroup, ClassPath.COMPILE, + AnnotationUtil.DEFAULT_FQN) || + hasResource(sourceGroup, ClassPath.SOURCE, AnnotationUtil.DEFAULT_FQN); + if ( defaultFound ){ + hasDefault = true; + } + boolean producesFound = hasResource(sourceGroup, ClassPath.COMPILE, + AnnotationUtil.PRODUCES_FQN) || + hasResource(sourceGroup, ClassPath.SOURCE, AnnotationUtil.PRODUCES_FQN); + if ( producesFound ){ + hasProduces = true; + } + boolean dependentFound = hasResource(sourceGroup, ClassPath.COMPILE, + AnnotationUtil.DEPENDENT) || + hasResource(sourceGroup, ClassPath.SOURCE, AnnotationUtil.DEPENDENT); + if ( dependentFound ){ + hasDependent = true; + } + } + + return hasDefault && hasProduces && hasDependent; + } + + static boolean hasResource(SourceGroup group , String classPathType, String fqn){ + ClassPath classPath = ClassPath.getClassPath(group.getRootFolder(), classPathType); + String path = fqn.replace('.', '/'); + if ( ClassPath.SOURCE.equals( classPathType ) ){ + path = path+".java"; // NOI18N + } + else { + path = path+".class"; // NOI18N + } + if (classPath == null) { + return false; + } + + return classPath.findResource(path) != null; + } + + /** + * Compilation controller from metamodel could not be used for getting + * TreePath via dot because it is not based on one FileObject ( Document ). + * So this method is required for searching Element at dot. + * If appropriate element is found it's name is placed into list + * along with name of containing type. + * Resulted element could not be used in metamodel for injectable + * access. This is because element was gotten via other Compilation + * controller so it is from other model. + */ + static boolean getVariableElementAtDot( final JTextComponent component, + final Object[] variable , final boolean showStatusOnError) + { + return getVariableElementAtDot(component, variable, showStatusOnError, + CARET_POSITION_STRATEGY); + } + + /** + * Compilation controller from metamodel could not be used for getting + * TreePath via dot because it is not based on one FileObject ( Document ). + * So this method is required for searching Element at dot. + * If appropriate element is found it's name is placed into list + * along with name of containing type. + * Resulted element could not be used in metamodel for injectable + * access. This is because element was gotten via other Compilation + * controller so it is from other model. + */ + static boolean getVariableElementAtDot( final JTextComponent component, + final Object[] variable , final boolean showStatusOnError, + final PositionStrategy strategy) + { + + JavaSource javaSource = JavaSource.forDocument(component.getDocument()); + if ( javaSource == null ){ + Toolkit.getDefaultToolkit().beep(); + return false; + } + try { + javaSource.runUserActionTask( new Task(){ + @Override + public void run(CompilationController controller) throws Exception { + controller.toPhase( Phase.ELEMENTS_RESOLVED ); + int dot = strategy.getOffset(component); + TreePath tp = controller.getTreeUtilities().pathFor(dot); + Element contextElement = controller.getTrees().getElement(tp ); + if ( contextElement == null ){ + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage( + WebBeansActionHelper.class, + "LBL_ElementNotFound")); + return; + } + Element element = getContextElement(contextElement, controller); + if ( element == null ){ + return; + } + if ( !( element instanceof VariableElement) && showStatusOnError){ + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage( + WebBeansActionHelper.class, + "LBL_NotVariableElement", + StatusDisplayer.IMPORTANCE_ERROR_HIGHLIGHT)); + return; + } + else { + if ( element.getKind() == ElementKind.FIELD ){ + ElementHandle handle = + ElementHandle.create((VariableElement)element); + variable[0] = handle; + variable[1] = element.getSimpleName().toString(); + variable[2] = InspectActionId.INJECTABLES_CONTEXT; + } + else { + setVariablePath(variable, controller, element); + } + } + } + }, true ); + } + catch(IOException e ){ + Logger.getLogger( GoToInjectableAtCaretAction.class.getName()). + log( Level.INFO, e.getMessage(), e); + } + return variable[1] !=null ; + } + + /** + * Based on the context element method chooses different element. + * If element is not "injection" ( not injection point and has no + * injection context ) method sets the error message in the status + * and return null. + */ + static Element getContextElement(Element element , + CompilationController controller ) + { + if ( element instanceof TypeElement ){ + if ( hasAnnotation(element, DECORATOR) ){ + List fieldsIn = ElementFilter.fieldsIn( + controller.getElements().getAllMembers((TypeElement)element)); + for (VariableElement variableElement : fieldsIn) { + if ( hasAnnotation(variableElement, DELEGATE)){ + return variableElement; + } + } + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage( + WebBeansActionHelper.class, + "LBL_NotDecorator")); + } + return null; + } + return element; + } + + static boolean hasAnnotation(Element element,String fqn){ + List annotationMirrors = + element.getAnnotationMirrors(); + for (AnnotationMirror annotationMirror : annotationMirrors) { + DeclaredType annotationType = annotationMirror.getAnnotationType(); + Element annotationElement = annotationType.asElement(); + if ( annotationElement instanceof TypeElement ){ + Name qualifiedName = ((TypeElement)annotationElement). + getQualifiedName(); + if ( qualifiedName.contentEquals(fqn)){ + return true; + } + } + } + return false; + } + + static boolean getClassAtDot( + final JTextComponent component , final Object[] subject ) + { + return getClassAtDot(component, subject, CARET_POSITION_STRATEGY); + } + + static boolean getClassAtDot( + final JTextComponent component , final Object[] subject, + final PositionStrategy strategy ) + { + JavaSource javaSource = JavaSource.forDocument(component.getDocument()); + if ( javaSource == null ){ + Toolkit.getDefaultToolkit().beep(); + return false; + } + try { + javaSource.runUserActionTask( new Task(){ + @Override + public void run(CompilationController controller) throws Exception { + controller.toPhase( Phase.ELEMENTS_RESOLVED ); + int dot = strategy.getOffset(component); + TreePath tp = controller.getTreeUtilities() + .pathFor(dot); + Element element = controller.getTrees().getElement(tp ); + if ( element == null ){ + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage( + WebBeansActionHelper.class, + "LBL_ElementNotFound")); + return; + } + if ( element instanceof TypeElement ){ + subject[0] = ElementHandle.create(element); + subject[1] = element.getSimpleName(); + subject[2] = InspectActionId.CLASS_CONTEXT; + } + } + }, true ); + } + catch(IOException e ){ + Logger.getLogger( WebBeansActionHelper.class.getName()). + log( Level.WARNING, e.getMessage(), e); + } + + return subject[0]!=null; + } + + static boolean getMethodAtDot( + final JTextComponent component , final Object[] subject , + final PositionStrategy strategy) + { + JavaSource javaSource = JavaSource.forDocument(component.getDocument()); + if ( javaSource == null ){ + Toolkit.getDefaultToolkit().beep(); + return false; + } + try { + javaSource.runUserActionTask( new Task(){ + @Override + public void run(CompilationController controller) throws Exception { + controller.toPhase( Phase.ELEMENTS_RESOLVED ); + int dot = strategy.getOffset(component); + TreePath tp = controller.getTreeUtilities() + .pathFor(dot); + Element element = controller.getTrees().getElement(tp ); + if ( element == null ){ + StatusDisplayer.getDefault().setStatusText( + NbBundle.getMessage( + WebBeansActionHelper.class, + "LBL_ElementNotFound")); + return; + } + if ( element instanceof ExecutableElement ){ + subject[0] = ElementHandle.create(element); + subject[1] = element.getSimpleName(); + subject[2] = InspectActionId.METHOD_CONTEXT; + } + else if ( element instanceof VariableElement ){ + Element enclosingElement = element.getEnclosingElement(); + if ( enclosingElement instanceof ExecutableElement && + hasAnnotation(element, OBSERVES_ANNOTATION)) + { + subject[0] = ElementHandle.create(enclosingElement); + subject[1] = enclosingElement.getSimpleName(); + subject[2] = InspectActionId.METHOD_CONTEXT; + } + } + } + }, true ); + } + catch(IOException e ){ + Logger.getLogger( WebBeansActionHelper.class.getName()). + log( Level.WARNING, e.getMessage(), e); + } + + return subject[0]!=null; + } + + static boolean getMethodAtDot( + final JTextComponent component , final Object[] subject ) + { + return getMethodAtDot(component, subject, CARET_POSITION_STRATEGY ); + } + + public static boolean getContextEventInjectionAtDot( + final JTextComponent component, final Object[] variable , + final PositionStrategy strategy ) + { + try { + ParserManager.parse(Collections.singleton (Source.create( + component.getDocument())), new UserTask() + { + @Override + public void run(ResultIterator resultIterator) throws Exception { + Result resuslt = resultIterator.getParserResult ( + strategy.getOffset(component)); + CompilationController controller = CompilationController.get( + resuslt); + if (controller == null || controller.toPhase(Phase.RESOLVED). + compareTo(Phase.RESOLVED) < 0) + { + return; + } + Token[] token = new Token[1]; + int[] span = getIdentifierSpan( component.getDocument(), + strategy.getOffset(component), token); + + if (span == null) { + return ; + } + + int exactOffset = controller.getSnapshot(). + getEmbeddedOffset(span[0] + 1); + TreePath path = controller.getTreeUtilities().pathFor(exactOffset); + TreePath parent = path.getParentPath(); + if (parent != null) { + Tree parentLeaf = parent.getLeaf(); + if ( parentLeaf.getKind() == Kind.METHOD_INVOCATION){ + ExpressionTree select = ((MethodInvocationTree)parentLeaf). + getMethodSelect(); + /* + * Identifier case should be ignored because in this case + * method is called on 'this' instance . Which is never + * managed by J2EE container as Event injectable. + */ + if ( select.getKind() == Kind.MEMBER_SELECT ){ + Scope scope = controller.getTrees().getScope(path); + Element subjectClass = scope.getEnclosingClass(); + Element method = controller.getTrees().getElement( + new TreePath(path, select)); + Element caller = controller.getTrees().getElement( + new TreePath(path, ((MemberSelectTree)select).getExpression())); + String methodName = method.getSimpleName().toString(); + if ( FIRE.equals( methodName) && + method instanceof ExecutableElement && + caller instanceof VariableElement ) + { + String variableName = caller.getSimpleName().toString(); + TypeElement enclosingTypeElement = + controller.getElementUtilities(). + enclosingTypeElement( method); + String fqnMethodClass = enclosingTypeElement. + getQualifiedName().toString(); + if( EVENT_INTERFACE.equals(fqnMethodClass)){ + List fields = + ElementFilter.fieldsIn + ( controller.getElements().getAllMembers( + (TypeElement)subjectClass)); + for (VariableElement var : fields) { + String varName = var.getSimpleName().toString(); + if ( variableName.equals( varName )){ + ElementHandle handle = + ElementHandle.create(var); + variable[0]= handle; + variable[1]= varName; + variable[2]= InspectActionId.OBSERVERS_CONTEXT; + return; + } + } + } + } + } + } + } + } + }); + } + catch (ParseException e) { + throw new IllegalStateException(e); + } + return variable[1] !=null ; + } + + public static boolean getContextEventInjectionAtDot( + final JTextComponent component, final Object[] variable ) + { + return getContextEventInjectionAtDot(component, variable, CARET_POSITION_STRATEGY); + } + + static void showInjectablesDialog( MetadataModel metamodel, + WebBeansModel model, Object[] subject, + InjectablesModel uiModel , String name , + org.netbeans.modules.jakarta.web.beans.api.model.Result result ) + { + subject[2] = InspectActionId.INJECTABLES_CONTEXT; + StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage( + InjectablesModel.class, WAIT_NODE)); // NOI18N + JDialog dialog = ResizablePopup.getDialog(); + String title = NbBundle.getMessage(WebBeansActionHelper.class, + "TITLE_Injectables" , name );//NOI18N + dialog.setTitle( title ); + dialog.setContentPane( new BindingsPanel(subject, metamodel, model, + uiModel, result )); + dialog.setVisible( true ); + } + + static void showEventsDialog( MetadataModel metaModel , + WebBeansModel model,Object[] subject, + EventsModel uiModel , String name ) + { + subject[2] = InspectActionId.METHOD_CONTEXT; + StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage( + InjectablesModel.class, WAIT_NODE)); + JDialog dialog = ResizablePopup.getDialog(); + String title = NbBundle.getMessage(WebBeansActionHelper.class, + "TITLE_Events" , name );//NOI18N + dialog.setTitle( title ); + dialog.setContentPane( new EventsPanel(subject, metaModel, + model ,uiModel )); + dialog.setVisible( true ); + } + + static void showObserversDialog( List methods , + MetadataModel metaModel , WebBeansModel model, + Object[] subject, ObserversModel uiModel , + String name ) + { + subject[2] = InspectActionId.OBSERVERS_CONTEXT; + StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage( + InjectablesModel.class, WAIT_NODE)); + JDialog dialog = ResizablePopup.getDialog(); + String title = NbBundle.getMessage(WebBeansActionHelper.class, + "TITLE_Observers" , name );//NOI18N + dialog.setTitle( title ); + dialog.setContentPane( new ObserversPanel(subject, metaModel, + model ,uiModel )); + dialog.setVisible( true ); + + } + + public static void showDecoratorsDialog( + MetadataModel metaModel, WebBeansModel model, + Object[] subject, DecoratorsModel uiModel, String name ) + { + subject[2] = InspectActionId.CLASS_CONTEXT; + StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage( + InjectablesModel.class, WAIT_NODE)); + JDialog dialog = ResizablePopup.getDialog(); + String title = NbBundle.getMessage(WebBeansActionHelper.class, + "TITLE_Decorators" , name );//NOI18N + dialog.setTitle( title ); + dialog.setContentPane( new DecoratorsPanel(subject, metaModel, + model ,uiModel )); + dialog.setVisible( true ); + } + + static void showInterceptorsDialog( + MetadataModel metaModel, WebBeansModel model, + Object[] subject, InterceptorsModel uiModel, String name , + InterceptorsResult result ) + { + subject[2] = InspectActionId.CLASS_CONTEXT; + StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage( + InjectablesModel.class, WAIT_NODE)); + JDialog dialog = ResizablePopup.getDialog(); + String title = NbBundle.getMessage(WebBeansActionHelper.class, + "TITLE_Interceptors" , name );//NOI18N + dialog.setTitle( title ); + dialog.setContentPane( new InterceptorsPanel(subject, metaModel, + model ,uiModel , result)); + dialog.setVisible( true ); + } + + public static LinkedHashSet getEnabledDecorators( + Collection decorators,BeansModel beansModel, + LinkedHashSet> enabledHandles, + CompilationController controller) + + { + LinkedHashSet enabled = new LinkedHashSet(); + + Set foundDecorators = new HashSet( decorators ); + LinkedHashSet decoratorClasses = beansModel.getDecoratorClasses(); + for (String decorator : decoratorClasses) { + TypeElement enabledDecorator = controller.getElements(). + getTypeElement( decorator ); + if ( foundDecorators.contains(enabledDecorator) ){ + enabled.add( enabledDecorator ); + if ( enabledHandles!= null){ + enabledHandles.add( ElementHandle.create( enabledDecorator)); + } + } + } + return enabled; + } + + public static VariableElement findVariable( final WebBeansModel model, + final Object[] variablePath ) + { + if ( variablePath[0] == null ){ + StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage( + WebBeansActionHelper.class, + "LBL_VariableNotFound", variablePath[1])); + return null ; + } + Element element = ((ElementHandle)variablePath[0]).resolve( + model.getCompilationController()); + if ( element == null ){ + StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage( + WebBeansActionHelper.class, + "LBL_VariableNotFound", variablePath[1])); + return null ; + } + VariableElement var = null; + ExecutableElement method = null; + if ( element.getKind() == ElementKind.FIELD){ + var = (VariableElement)element; + } + else { + method = (ExecutableElement)element; + List parameters = method.getParameters(); + for (VariableElement variableElement : parameters) { + if (variableElement.getSimpleName().contentEquals( + variablePath[1].toString())) + { + var = variableElement; + } + } + } + + if (var == null) { + StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage( + WebBeansActionHelper.class, + "LBL_VariableNotFound", variablePath[1])); + } + return var; + } + + static int[] getIdentifierSpan(Document doc, int offset, Token[] token) { + FileObject fileObject = NbEditorUtilities.getFileObject( doc); + if (fileObject== null) { + //do nothing if FO is not attached to the document - the goto would not work anyway: + return null; + } + + TokenHierarchy th = TokenHierarchy.get(doc); + TokenSequence ts = SourceUtils.getJavaTokenSequence(th, offset); + + if (ts == null) + return null; + + ts.move(offset); + if (!ts.moveNext()) + return null; + + Token t = ts.token(); + + if (JavaTokenId.JAVADOC_COMMENT == t.id()) { + return null; + } else if (!USABLE_TOKEN_IDS.contains(t.id())) { + ts.move(offset - 1); + if (!ts.moveNext()) + return null; + t = ts.token(); + if (!USABLE_TOKEN_IDS.contains(t.id())) + return null; + } + + if (token != null) + token[0] = t; + + return new int [] {ts.offset(), ts.offset() + t.length()}; + } + + private static void setVariablePath( Object[] variableAtCaret, + CompilationController controller, Element element ) + { + Element parent = element.getEnclosingElement(); + if ( parent instanceof ExecutableElement ){ + ElementHandle handle = ElementHandle.create( + (ExecutableElement)parent ) ; + variableAtCaret[0] = handle; + variableAtCaret[1] = element.getSimpleName().toString(); + variableAtCaret[2] = InspectActionId.INJECTABLES_CONTEXT; + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/BeansResolver.xml b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/BeansResolver.xml new file mode 100644 index 000000000000..b017c8eb2331 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/BeansResolver.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/BeansXml.html b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/BeansXml.html new file mode 100644 index 000000000000..646cae17459e --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/BeansXml.html @@ -0,0 +1,29 @@ + + + + + + + +Creates a new beans.xml. + + diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Bundle.properties b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Bundle.properties new file mode 100644 index 000000000000..1065902b7fda --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Bundle.properties @@ -0,0 +1,34 @@ +OpenIDE-Module-Display-Category=Jakarta EE +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +OpenIDE-Module-Name=Jakarta EE CDI Support +OpenIDE-Module-Short-Description=Contexts and Dependency Injection Support for Jakarta EE +Templates/CDI_JakartaEE=Contexts and Dependency Injection (JakartaEE) +Templates/CDI_JakartaEE/beans.xml=beans.xml (CDI Configuration File) +Templates/CDI_JakartaEE/Interceptor.java=Interceptor Binding Type +Templates/CDI_JakartaEE/Qualifier.java=Qualifier Type +Templates/CDI_JakartaEE/Scope.java=Scope Type +Templates/CDI_JakartaEE/Stereotype.java=Stereotype + +DSCR_InjectionPoint=CDI Injection Point +DSCR_Decorated=CDI Decorated Bean +DSCR_Delegate=CDI Delegate Injection Point +DSCR_Event=CDI Event +DSCR_Observer=CDI Observer +DSCR_Intercepted=CDI Intercepted Element + +Loaders/text/x-beans-jakarta+xml/Factories/org-netbeans-modules-jakarta-web-beans-BeansDataLoader.instance=Persistence Unit Files diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Interceptor.html b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Interceptor.html new file mode 100644 index 000000000000..07b493414517 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Interceptor.html @@ -0,0 +1,29 @@ + + + + + + + +Creates a new interceptor binding type. + + diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Interceptor.template b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Interceptor.template new file mode 100644 index 000000000000..972a940698fc --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Interceptor.template @@ -0,0 +1,27 @@ +<#assign licenseFirst = "/*"> +<#assign licensePrefix = " * "> +<#assign licenseLast = " */"> +<#include "${project.licensePath}"> + +<#if package?? && package != ""> +package ${package}; + + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import javax.interceptor.InterceptorBinding; + +/** + * + * @author ${user} + */ +@Inherited +@InterceptorBinding +@Retention(RUNTIME) +@Target({METHOD, TYPE}) +public @interface ${name} { +} \ No newline at end of file diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Qualifier.html b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Qualifier.html new file mode 100644 index 000000000000..aef095f91785 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Qualifier.html @@ -0,0 +1,29 @@ + + + + + + + +Creates a new qualifier type. + + diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Qualifier.template b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Qualifier.template new file mode 100644 index 000000000000..1f8fe0b7399a --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Qualifier.template @@ -0,0 +1,27 @@ +<#assign licenseFirst = "/*"> +<#assign licensePrefix = " * "> +<#assign licenseLast = " */"> +<#include "${project.licensePath}"> + +<#if package?? && package != ""> +package ${package}; + + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import jakarta.inject.Qualifier; + +/** + * + * @author ${user} + */ +@Qualifier +@Retention(RUNTIME) +@Target({METHOD, FIELD, PARAMETER, TYPE}) +public @interface ${name} { +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Scope.html b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Scope.html new file mode 100644 index 000000000000..f0ffbfb2e888 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Scope.html @@ -0,0 +1,29 @@ + + + + + + + +Creates a new scope type. + + diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Scope.template b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Scope.template new file mode 100644 index 000000000000..9c9c52a8b10c --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Scope.template @@ -0,0 +1,28 @@ +<#assign licenseFirst = "/*"> +<#assign licensePrefix = " * "> +<#assign licenseLast = " */"> +<#include "${project.licensePath}"> + +<#if package?? && package != ""> +package ${package}; + + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import jakarta.inject.Scope; + +/** + * + * @author ${user} + */ +@Inherited +@Scope // or @jakarta.enterprise.context.NormalScope +@Retention(RUNTIME) +@Target({METHOD, FIELD, TYPE}) +public @interface ${name} { +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Stereotype.html b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Stereotype.html new file mode 100644 index 000000000000..5628a029e607 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Stereotype.html @@ -0,0 +1,29 @@ + + + + + + + +Creates a new stereotype. + + diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Stereotype.template b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Stereotype.template new file mode 100644 index 000000000000..4d16fe1aa719 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/Stereotype.template @@ -0,0 +1,26 @@ +<#assign licenseFirst = "/*"> +<#assign licensePrefix = " * "> +<#assign licenseLast = " */"> +<#include "${project.licensePath}"> + +<#if package?? && package != ""> +package ${package}; + + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import jakarta.enterprise.inject.Stereotype; + +/** + * + * @author ${user} + */ +@Stereotype +@Retention(RUNTIME) +@Target({METHOD, FIELD, TYPE}) +public @interface ${name} { +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/delegate.png b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/delegate.png new file mode 100644 index 000000000000..b1e761f2c3aa Binary files /dev/null and b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/delegate.png differ diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/event.png b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/event.png new file mode 100644 index 000000000000..6c610a399b5a Binary files /dev/null and b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/event.png differ diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/injection_point.png b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/injection_point.png new file mode 100644 index 000000000000..8c465f40359e Binary files /dev/null and b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/injection_point.png differ diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/layer.xml b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/layer.xml new file mode 100644 index 000000000000..10da46a7d0e3 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/layer.xml @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/observer.png b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/observer.png new file mode 100644 index 000000000000..4f028843b0f1 Binary files /dev/null and b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/observer.png differ diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/org-netbeans-modules-jakarta-web-beans-annotations-decorated-bean.xml b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/org-netbeans-modules-jakarta-web-beans-annotations-decorated-bean.xml new file mode 100644 index 000000000000..039e8b2c22fd --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/org-netbeans-modules-jakarta-web-beans-annotations-decorated-bean.xml @@ -0,0 +1,30 @@ + + + + diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/org-netbeans-modules-jakarta-web-beans-annotations-delegate-point.xml b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/org-netbeans-modules-jakarta-web-beans-annotations-delegate-point.xml new file mode 100644 index 000000000000..308dadff5ea4 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/org-netbeans-modules-jakarta-web-beans-annotations-delegate-point.xml @@ -0,0 +1,30 @@ + + + + diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/org-netbeans-modules-jakarta-web-beans-annotations-event.xml b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/org-netbeans-modules-jakarta-web-beans-annotations-event.xml new file mode 100644 index 000000000000..0ffb04f49eeb --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/org-netbeans-modules-jakarta-web-beans-annotations-event.xml @@ -0,0 +1,30 @@ + + + + diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/org-netbeans-modules-jakarta-web-beans-annotations-injection-point.xml b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/org-netbeans-modules-jakarta-web-beans-annotations-injection-point.xml new file mode 100644 index 000000000000..664798ff0272 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/org-netbeans-modules-jakarta-web-beans-annotations-injection-point.xml @@ -0,0 +1,30 @@ + + + + diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/org-netbeans-modules-jakarta-web-beans-annotations-intercepted.xml b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/org-netbeans-modules-jakarta-web-beans-annotations-intercepted.xml new file mode 100644 index 000000000000..0b5d47151af3 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/org-netbeans-modules-jakarta-web-beans-annotations-intercepted.xml @@ -0,0 +1,30 @@ + + + + diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/org-netbeans-modules-jakarta-web-beans-annotations-observer.xml b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/org-netbeans-modules-jakarta-web-beans-annotations-observer.xml new file mode 100644 index 000000000000..0a1c101aef0f --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/resources/org-netbeans-modules-jakarta-web-beans-annotations-observer.xml @@ -0,0 +1,30 @@ + + + + diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/wizard/BeansXmlIterator.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/wizard/BeansXmlIterator.java new file mode 100644 index 000000000000..fa9ebb22981b --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/wizard/BeansXmlIterator.java @@ -0,0 +1,322 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.jakarta.web.beans.wizard; + +import java.awt.Component; +import java.io.IOException; +import java.util.*; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.event.ChangeListener; +import org.netbeans.api.j2ee.core.Profile; +import org.netbeans.api.java.project.JavaProjectConstants; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.api.project.Sources; +import org.netbeans.modules.j2ee.api.ejbjar.Car; +import org.netbeans.modules.j2ee.api.ejbjar.EjbJar; +import org.netbeans.modules.j2ee.common.J2eeProjectCapabilities; +import org.netbeans.modules.j2ee.common.dd.DDHelper; +import org.netbeans.modules.web.api.webmodule.WebModule; +import org.netbeans.modules.web.api.webmodule.WebProjectConstants; +import org.netbeans.modules.jakarta.web.beans.CdiUtil; +import org.netbeans.spi.project.ui.templates.support.Templates; +import org.netbeans.spi.project.ui.templates.support.Templates.SimpleTargetChooserBuilder; +import org.openide.WizardDescriptor; +import org.openide.WizardDescriptor.Panel; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.loaders.DataObject; +import org.openide.loaders.TemplateWizard; +import org.openide.util.Exceptions; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; + +/** + * A template wizard operator for new beans.xml + */ +public class BeansXmlIterator implements TemplateWizard.Iterator { + + private enum J2eeProjectType { + WAR, + JAR, + CAR + } + + private static final String WEB_INF = "WEB-INF"; // NOI18N + private static final String META_INF = "META-INF"; // NOI18N + + private int index; + private static final String defaultName = "beans"; //NOI18N + + private transient WizardDescriptor.Panel[] panels; + private transient J2eeProjectType type; + + @Override + public Set instantiate(TemplateWizard wizard) throws IOException { + String targetName = Templates.getTargetName(wizard); + FileObject targetDir = Templates.getTargetFolder(wizard); + Project project = Templates.getProject(wizard); + Profile profile = null; + if (project != null) { + J2eeProjectCapabilities cap = J2eeProjectCapabilities.forProject(project); + if (cap != null && cap.isCdi40Supported()) { + profile = Profile.JAKARTA_EE_10_FULL; + } else if (cap != null && cap.isCdi30Supported()) { + profile = Profile.JAKARTA_EE_9_FULL; + } else if (cap != null && cap.isCdi20Supported()) { + profile = Profile.JAVA_EE_8_FULL; + } else if (cap != null && cap.isCdi11Supported()) { + profile = Profile.JAVA_EE_7_FULL; + } + } + FileObject fo = DDHelper.createBeansXml(profile != null ? profile : Profile.JAVA_EE_6_FULL, targetDir, targetName); + if (fo != null) { + if ( project != null ){ + CdiUtil logger = project.getLookup().lookup( CdiUtil.class ); + if (logger != null){ + logger.log("USG_CDI_BEANS_WIZARD", BeansXmlIterator.class, + new Object[]{project.getClass().getName()}, true); + } + } + return Collections.singleton(DataObject.find(fo)); + } + else { + return Collections.EMPTY_SET; + } + } + + @Override + public void initialize(TemplateWizard wizard) { + WizardDescriptor.Panel folderPanel; + Project project = Templates.getProject( wizard ); + + FileObject targetFolder = getTargetFolder(project); + + Sources sources = project.getLookup().lookup(Sources.class); + SourceGroup[] sourceGroups; + String parentFolder = null; + if ( type == J2eeProjectType.WAR){ + sourceGroups = sources.getSourceGroups(WebProjectConstants.TYPE_DOC_ROOT); + if ( targetFolder!=null && targetFolder.getFileObject(defaultName+".xml")!=null){ + parentFolder = WEB_INF; + } + } + else { + if ( type != null && + targetFolder!=null && targetFolder.getFileObject(defaultName+".xml")!=null ) + { + parentFolder = targetFolder.getName(); + } + sourceGroups = sources.getSourceGroups(Sources.TYPE_GENERIC); + } + + SimpleTargetChooserBuilder builder = Templates. + buildSimpleTargetChooser(project, sourceGroups); + + builder = builder.bottomPanel( new FakePanel(parentFolder)); + folderPanel = builder.create(); + + panels = new WizardDescriptor.Panel[] { folderPanel }; + + // Creating steps. + Object prop = wizard.getProperty (WizardDescriptor.PROP_CONTENT_DATA); // NOI18N + String[] beforeSteps = null; + if (prop instanceof String[]) { + beforeSteps = (String[])prop; + } + String[] steps = createSteps(beforeSteps, panels); + + for (int i = 0; i < panels.length; i++) { + JComponent jc = (JComponent)panels[i].getComponent (); + if (steps[i] == null) { + steps[i] = jc.getName (); + } + jc.putClientProperty (WizardDescriptor.PROP_CONTENT_SELECTED_INDEX, i); + jc.putClientProperty (WizardDescriptor.PROP_CONTENT_DATA, steps); + } + + Templates.setTargetName(wizard, defaultName); + Templates.setTargetFolder(wizard, targetFolder ); + } + + private FileObject getTargetFolder(Project project) { + WebModule wm = WebModule.getWebModule(project.getProjectDirectory()); + if (wm != null) { + FileObject webInf = wm.getWebInf(); + if (webInf == null && wm.getDocumentBase() != null) { + try { + webInf = FileUtil.createFolder(wm.getDocumentBase(), WEB_INF); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + } + type = J2eeProjectType.WAR; + return webInf; + } + else { + EjbJar ejbs[] = EjbJar.getEjbJars(project); + if (ejbs.length > 0) { + type = J2eeProjectType.JAR; + return ejbs[0].getMetaInf(); + } else { + Car cars[] = Car.getCars(project); + if (cars.length > 0) { + type = J2eeProjectType.CAR; + return cars[0].getMetaInf(); + } + } + } + Sources sources = project.getLookup().lookup(Sources.class); + SourceGroup[] sourceGroups = sources.getSourceGroups( + JavaProjectConstants.SOURCES_TYPE_JAVA); + if ( sourceGroups.length >0 ){ + FileObject metaInf = sourceGroups[0].getRootFolder().getFileObject( + META_INF ); + if ( metaInf == null ){ + try { + metaInf = FileUtil.createFolder( + sourceGroups[0].getRootFolder(), META_INF); + } + catch( IOException e ){ + Exceptions.printStackTrace(e); + } + } + if ( metaInf != null ){ + return metaInf; + } + } + return project.getProjectDirectory(); + } + + @Override + public void uninitialize(TemplateWizard wiz) { + panels = null; + } + + @Override + public Panel current() { + return panels[index]; + } + + @Override + public String name() { + return NbBundle.getMessage(BeansXmlIterator.class, "TITLE_x_of_y", + index + 1, panels.length); + } + + @Override + public boolean hasNext() { + return index < panels.length - 1; + } + + @Override + public boolean hasPrevious() { + return index > 0; + } + + @Override + public void nextPanel() { + if (! hasNext ()) throw new NoSuchElementException (); + index++; + } + + @Override + public void previousPanel() { + if (! hasPrevious ()) throw new NoSuchElementException (); + index--; + } + + @Override + public void addChangeListener(ChangeListener l) { + } + + @Override + public void removeChangeListener(ChangeListener l) { + } + + public static String[] createSteps(String[] before, WizardDescriptor.Panel[] panels) { + //assert panels != null; + // hack to use the steps set before this panel processed + int diff = 0; + if (before == null) { + before = new String[0]; + } else if (before.length > 0) { + diff = ("...".equals (before[before.length - 1])) ? 1 : 0; // NOI18N + } + String[] res = new String[ (before.length - diff) + panels.length]; + for (int i = 0; i < res.length; i++) { + if (i < (before.length - diff)) { + res[i] = before[i]; + } else { + res[i] = panels[i - before.length + diff].getComponent ().getName (); + } + } + return res; + } + + static class FakePanel implements Panel { + + private String folder ; + + FakePanel(String folder ){ + this.folder = folder; + } + + @Override + public Component getComponent() { + return new JPanel(); + } + + @Override + public HelpCtx getHelp() { + return null; + } + + @Override + public void readSettings(Object settings) { + if ( folder!=null ){ + ((WizardDescriptor)settings).putProperty( + WizardDescriptor.PROP_ERROR_MESSAGE, + NbBundle.getMessage( BeansXmlIterator.class , + "ERR_BeansAlreadyExists", folder)); + } + } + + @Override + public void storeSettings(Object settings) { + } + + @Override + public boolean isValid() { + return folder == null; + } + + @Override + public void addChangeListener(ChangeListener l) { + } + + @Override + public void removeChangeListener(ChangeListener l) { + } + + } + +} \ No newline at end of file diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/wizard/Bundle.properties b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/wizard/Bundle.properties new file mode 100644 index 000000000000..45353e4bd9b4 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/wizard/Bundle.properties @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +TITLE_x_of_y={0} of {1} + +ERR_BeansAlreadyExists = There is already file beans.xml in the {0} directory +USG_CDI_BEANS_WIZARD=beans.xml file is created in the project "{0}". diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/AlternativeElement.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/AlternativeElement.java new file mode 100644 index 000000000000..8dff27e086d3 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/AlternativeElement.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml; + + +/** + * @author ads + * + */ +public interface AlternativeElement extends WebBeansComponent { + + String ALTERNATIVE_ELEMENT = "alternative-element"; //NOI18N +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/Alternatives.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/Alternatives.java new file mode 100644 index 000000000000..c02605303bfc --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/Alternatives.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml; + +import java.util.List; + + +/** + * @author ads + * + */ +public interface Alternatives extends BeansElement { + + String ALTERNATIVES = "alternatives"; // NOI18N + + List getClasses(); + + List getSterrotypes(); + + List getElements(); + void addElement( AlternativeElement element ); + void addElement( int index , AlternativeElement element ); + void removeElement( AlternativeElement element ); +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/BeanClass.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/BeanClass.java new file mode 100644 index 000000000000..4c1c074102b2 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/BeanClass.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml; + + +/** + * @author ads + * + */ +public interface BeanClass extends AlternativeElement { + + String CLASS = BeansElement.CLASS; + + String getBeanClass(); + void setBeanClass( String value ); +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/BeanClassContainer.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/BeanClassContainer.java new file mode 100644 index 000000000000..fe5a5dda6c0c --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/BeanClassContainer.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml; + +import java.util.List; + + +/** + * @author ads + * + */ +public interface BeanClassContainer extends WebBeansComponent { + + List getClasses(); + + List getBeansClasses(); + void addBeanClass( BeanClass clazz ); + void addBeanClass( int index , BeanClass clazz ); + void removeBeanClass( BeanClass clazz ); +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/Beans.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/Beans.java new file mode 100644 index 000000000000..84a1e9e4cb8e --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/Beans.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml; + +import java.util.List; + + +/** + * + * This model represents beans.xml OM. + * It is based on schema file last changed at 2009-12-02 + * http://fisheye.jboss.org/browse/~raw,r=5197/weld/api/trunk/cdi/src/main/resources/beans.xsd. + * + * @author ads + * + */ +public interface Beans extends WebBeansComponent { + + String BEANS_ELEMENT = "beans-element"; // NOI18N + + String BEANS = "beans"; // NOI18N + + List getElements(); + void addElement( BeansElement element ); + void removeElement( BeansElement element ); + void addElement( int index , BeansElement element ); +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/BeansAttributes.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/BeansAttributes.java new file mode 100644 index 000000000000..a35d5bda96f5 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/BeansAttributes.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml; + +import org.netbeans.modules.xml.xam.dom.Attribute; + +/** + * + * @author Martin Fousek + */ +public enum BeansAttributes implements Attribute { + XMLNS("xmlns", String.class), //NOI18N + VERSION("version", String.class), //NOI18N + BEAN_DISCOVERY_MODE("bean-discovery-mode", String.class); //NOI18N + + private final String name; + private final Class type; + + private BeansAttributes(String name, Class type) { + this.name = name; + this.type = type; + } + + @Override + public String getName() { + return name; + } + + @Override + public Class getType() { + return type; + } + + @Override + public Class getMemberType() { + return null; + } +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/BeansElement.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/BeansElement.java new file mode 100644 index 000000000000..bc34d82b3040 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/BeansElement.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml; + + +/** + * Represent child of Beans interface. + * @author ads + * + */ +public interface BeansElement extends WebBeansComponent { + + String CLASS = "class"; //NOI18N + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/Decorators.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/Decorators.java new file mode 100644 index 000000000000..c8d3c85e25a2 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/Decorators.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml; + + + +/** + * @author ads + * + */ +public interface Decorators extends BeansElement, BeanClassContainer { + + String DECORATORS = "decorators"; // NOI18N + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/Interceptors.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/Interceptors.java new file mode 100644 index 000000000000..96fdac7264e7 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/Interceptors.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml; + + + +/** + * @author ads + * + */ +public interface Interceptors extends BeansElement, BeanClassContainer { + + String INTERCEPTORS = "interceptors"; // NOI18N + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/Stereotype.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/Stereotype.java new file mode 100644 index 000000000000..3f5f61da9d85 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/Stereotype.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml; + + +/** + * @author ads + * + */ +public interface Stereotype extends AlternativeElement { + + String STEREOTYPE = "stereotype"; // NOI18N + + String getStereotype(); + void setStereotype( String value ); +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/WebBeansComponent.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/WebBeansComponent.java new file mode 100644 index 000000000000..f9bb864ee920 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/WebBeansComponent.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml; + +import org.netbeans.modules.xml.xam.dom.DocumentComponent; + + +/** + * @author ads + * + */ +public interface WebBeansComponent extends DocumentComponent { + + String WEB_BEANS_NAMESPACE_OLD = "http://java.sun.com/xml/ns/javaee"; // NOI18N + String WEB_BEANS_NAMESPACE = "http://xmlns.jcp.org/xml/ns/javaee"; // NOI18N + + WebBeansModel getModel(); + + Class getComponentType(); + + void accept( WebBeansVisitor visitor ); +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/WebBeansComponentFactory.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/WebBeansComponentFactory.java new file mode 100644 index 000000000000..d0416d846e6b --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/WebBeansComponentFactory.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml; + +import org.w3c.dom.Element; + + +/** + * @author ads + * + */ +public interface WebBeansComponentFactory { + + WebBeansComponent createComponent( Element element, WebBeansComponent context); + + Beans createBeans(); + Decorators createDecorators(); + Interceptors createInterceptors(); + Alternatives createAlternatives(); + BeanClass createBeanClass(); + Stereotype createStereotype(); +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/WebBeansModel.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/WebBeansModel.java new file mode 100644 index 000000000000..f977ba8acfaa --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/WebBeansModel.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml; + +import org.netbeans.modules.xml.xam.dom.DocumentModel; + + +/** + * @author ads + * + */ +public interface WebBeansModel extends DocumentModel { + + Beans getBeans(); + + WebBeansComponentFactory getFactory(); +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/WebBeansModelFactory.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/WebBeansModelFactory.java new file mode 100644 index 000000000000..a42939fde320 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/WebBeansModelFactory.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml; + +import org.netbeans.modules.jakarta.web.beans.xml.impl.WebBeansModelImpl; +import org.netbeans.modules.xml.xam.AbstractModelFactory; +import org.netbeans.modules.xml.xam.ModelSource; + + +/** + * @author ads + * + */ +public class WebBeansModelFactory extends AbstractModelFactory { + + private WebBeansModelFactory(){ + } + + public static WebBeansModelFactory getInstance(){ + return INSTANCE; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.xml.xam.AbstractModelFactory#createModel(org.netbeans.modules.xml.xam.ModelSource) + */ + @Override + public WebBeansModel createModel( ModelSource modelSource ) { + return new WebBeansModelImpl( modelSource ); + } + + @Override + public WebBeansModel getModel(ModelSource source) { + return super.getModel(source); + } + + private static final WebBeansModelFactory INSTANCE = new WebBeansModelFactory(); + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/WebBeansVisitor.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/WebBeansVisitor.java new file mode 100644 index 000000000000..4ef2a2386d21 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/WebBeansVisitor.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml; + + +/** + * @author ads + * + */ +public interface WebBeansVisitor { + + void visit( Beans beans ); + void visit( Interceptors interceptors ); + void visit( Decorators decorators ); + void visit( Alternatives alternatives ); + void visit( BeanClass clazz ); + void visit( Stereotype stereotype ); +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/AlternativesImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/AlternativesImpl.java new file mode 100644 index 000000000000..3b5cb44b8574 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/AlternativesImpl.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml.impl; + +import java.util.ArrayList; +import java.util.List; + +import org.netbeans.modules.jakarta.web.beans.xml.AlternativeElement; +import org.netbeans.modules.jakarta.web.beans.xml.Alternatives; +import org.netbeans.modules.jakarta.web.beans.xml.Stereotype; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + + +/** + * @author ads + * + */ +class AlternativesImpl extends BaseClassContainerImpl implements + Alternatives +{ + private final WebBeansModelImpl model; + + AlternativesImpl( WebBeansModelImpl model, Element e ) { + super(model, e); + this.model = model; + } + + AlternativesImpl( WebBeansModelImpl model) { + this(model, createNewElement( ALTERNATIVES , model )); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.Alternatives#addElement(org.netbeans.modules.jakarta.web.beans.xml.AlternativeElement) + */ + public void addElement( AlternativeElement element ) { + appendChild(AlternativeElement.ALTERNATIVE_ELEMENT, element); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.Alternatives#addElement(int, org.netbeans.modules.jakarta.web.beans.xml.AlternativeElement) + */ + public void addElement( int index, AlternativeElement element ) { + insertAtIndex(AlternativeElement.ALTERNATIVE_ELEMENT, element, index); + } + + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.Alternatives#getElements() + */ + public List getElements() { + return getChildren( AlternativeElement.class); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.Alternatives#getSterrotypes() + */ + public List getSterrotypes() { + NodeList nl = getPeer().getElementsByTagName(Stereotype.STEREOTYPE); + List result = new ArrayList( nl.getLength()); + if (nl != null) { + for (int i=0; i getComponentType() { + return Alternatives.class; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/BaseClassContainerImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/BaseClassContainerImpl.java new file mode 100644 index 000000000000..aa4cd866cfff --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/BaseClassContainerImpl.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml.impl; + +import java.util.ArrayList; +import java.util.List; + +import org.netbeans.modules.jakarta.web.beans.xml.BeansElement; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + + +/** + * @author ads + * + */ +abstract class BaseClassContainerImpl extends WebBeansComponentImpl { + + private final WebBeansModelImpl model; + + BaseClassContainerImpl( WebBeansModelImpl model, Element e ) { + super(model, e); + this.model = model; + } + + public List getClasses(){ + NodeList nl = getPeer().getElementsByTagName(BeansElement.CLASS); + List result = new ArrayList( nl.getLength()); + if (nl != null) { + for (int i=0; i getComponentType() { + return BeanClass.class; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/BeansImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/BeansImpl.java new file mode 100644 index 000000000000..7e6a5240d830 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/BeansImpl.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml.impl; + +import java.util.List; + +import org.netbeans.modules.jakarta.web.beans.xml.Beans; +import org.netbeans.modules.jakarta.web.beans.xml.BeansElement; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor; +import org.w3c.dom.Element; + + +/** + * @author ads + * + */ +class BeansImpl extends WebBeansComponentImpl implements Beans { + + BeansImpl( WebBeansModelImpl model, Element e ) { + super(model, e); + } + + BeansImpl( WebBeansModelImpl model) { + this(model, createNewElement( BEANS, model)); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.Beans#addElement(org.netbeans.modules.jakarta.web.beans.xml.BeansElement) + */ + public void addElement( BeansElement element ) { + appendChild(BEANS_ELEMENT, element ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.Beans#addElement(int, org.netbeans.modules.jakarta.web.beans.xml.BeansElement) + */ + public void addElement( int index, BeansElement element ) { + insertAtIndex( BEANS_ELEMENT, element, index); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.Beans#getElements() + */ + public List getElements() { + return getChildren( BeansElement.class ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.Beans#removeElement(org.netbeans.modules.jakarta.web.beans.xml.BeansElement) + */ + public void removeElement( BeansElement element ) { + removeChild( BEANS_ELEMENT, element ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent#accept(org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor) + */ + public void accept( WebBeansVisitor visitor ) { + visitor.visit( this ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent#getComponentType() + */ + public Class getComponentType() { + return Beans.class; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/ClassContainerImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/ClassContainerImpl.java new file mode 100644 index 000000000000..08c123462200 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/ClassContainerImpl.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml.impl; + +import java.util.List; + +import org.netbeans.modules.jakarta.web.beans.xml.BeanClass; +import org.netbeans.modules.jakarta.web.beans.xml.BeanClassContainer; +import org.w3c.dom.Element; + + +/** + * @author ads + * + */ +abstract class ClassContainerImpl extends BaseClassContainerImpl + implements BeanClassContainer +{ + + ClassContainerImpl( WebBeansModelImpl model, Element e ) { + super(model, e); + } + + + public void addBeanClass( BeanClass clazz ) { + appendChild(BeanClass.CLASS, clazz); + } + + public void addBeanClass( int index, BeanClass clazz ) { + insertAtIndex(BeanClass.CLASS, clazz, index); + } + + public List getBeansClasses() { + return getChildren( BeanClass.class ); + } + + public void removeBeanClass( BeanClass clazz ) { + removeChild( BeanClass.CLASS, clazz); + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/DecoratorsImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/DecoratorsImpl.java new file mode 100644 index 000000000000..e3080af180a4 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/DecoratorsImpl.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml.impl; + +import org.netbeans.modules.jakarta.web.beans.xml.Decorators; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor; +import org.w3c.dom.Element; + + +/** + * @author ads + * + */ +class DecoratorsImpl extends ClassContainerImpl implements Decorators { + + DecoratorsImpl( WebBeansModelImpl model, Element e ) { + super(model, e); + } + + DecoratorsImpl( WebBeansModelImpl model ) { + this(model, createNewElement( DECORATORS , model )); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent#accept(org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor) + */ + public void accept( WebBeansVisitor visitor ) { + visitor.visit( this ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent#getComponentType() + */ + public Class getComponentType() { + return Decorators.class; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/InterceptorsImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/InterceptorsImpl.java new file mode 100644 index 000000000000..d538abb58c1f --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/InterceptorsImpl.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml.impl; + +import org.netbeans.modules.jakarta.web.beans.xml.Interceptors; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor; +import org.w3c.dom.Element; + + +/** + * @author ads + * + */ +class InterceptorsImpl extends ClassContainerImpl implements Interceptors { + + InterceptorsImpl( WebBeansModelImpl model, Element e ) { + super(model, e); + } + + InterceptorsImpl( WebBeansModelImpl model ) { + super(model, createNewElement( INTERCEPTORS , model )); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent#accept(org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor) + */ + public void accept( WebBeansVisitor visitor ) { + visitor.visit(this ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent#getComponentType() + */ + public Class getComponentType() { + return Interceptors.class; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/StereotypeImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/StereotypeImpl.java new file mode 100644 index 000000000000..a1ca83bdb189 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/StereotypeImpl.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml.impl; + +import org.netbeans.modules.jakarta.web.beans.xml.Stereotype; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor; +import org.w3c.dom.Element; + + +/** + * @author ads + * + */ +class StereotypeImpl extends WebBeansComponentImpl implements Stereotype +{ + + StereotypeImpl( WebBeansModelImpl model, Element e ) { + super(model, e); + } + + StereotypeImpl( WebBeansModelImpl model) { + this(model, createNewElement(STEREOTYPE, model)); + } + + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.Stereotype#getStereotype() + */ + public String getStereotype() { + return getText(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.Stereotype#setStereotype(java.lang.String) + */ + public void setStereotype( String value ) { + setText(STEREOTYPE, value); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent#accept(org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor) + */ + public void accept( WebBeansVisitor visitor ) { + visitor.visit( this ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent#getComponentType() + */ + public Class getComponentType() { + return Stereotype.class; + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/SyncUpdateVisitor.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/SyncUpdateVisitor.java new file mode 100644 index 000000000000..72e345a8c554 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/SyncUpdateVisitor.java @@ -0,0 +1,171 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml.impl; + +import org.netbeans.modules.jakarta.web.beans.xml.AlternativeElement; +import org.netbeans.modules.jakarta.web.beans.xml.Alternatives; +import org.netbeans.modules.jakarta.web.beans.xml.BeanClass; +import org.netbeans.modules.jakarta.web.beans.xml.BeanClassContainer; +import org.netbeans.modules.jakarta.web.beans.xml.Beans; +import org.netbeans.modules.jakarta.web.beans.xml.BeansElement; +import org.netbeans.modules.jakarta.web.beans.xml.Decorators; +import org.netbeans.modules.jakarta.web.beans.xml.Interceptors; +import org.netbeans.modules.jakarta.web.beans.xml.Stereotype; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor; +import org.netbeans.modules.xml.xam.ComponentUpdater; + + +/** + * @author ads + * + */ +class SyncUpdateVisitor implements ComponentUpdater, WebBeansVisitor { + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor#visit(org.netbeans.modules.jakarta.web.beans.xml.Beans) + */ + public void visit( Beans beans ) { + assert false : "Should never add or remove beans root"; // NOI18N + } + + /* (non-Javadoc) + * @see org.netbeans.modules.xml.xam.ComponentUpdater#update(org.netbeans.modules.xml.xam.Component, org.netbeans.modules.xml.xam.Component, org.netbeans.modules.xml.xam.ComponentUpdater.Operation) + */ + public void update( WebBeansComponent target, WebBeansComponent child, + Operation operation ) + { + update(target, child, -1 , operation); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.xml.xam.ComponentUpdater#update(org.netbeans.modules.xml.xam.Component, org.netbeans.modules.xml.xam.Component, int, org.netbeans.modules.xml.xam.ComponentUpdater.Operation) + */ + public void update( WebBeansComponent target, WebBeansComponent child, + int index, Operation operation ) + { + assert target != null; + assert child != null; + assert operation == null || operation == Operation.ADD || + operation == Operation.REMOVE; + + myParent = target; + myIndex = index; + myOperation = operation; + child.accept(this); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor#visit(org.netbeans.modules.jakarta.web.beans.xml.Interceptors) + */ + public void visit( Interceptors interceptors ) { + visitBeanElement(interceptors); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor#visit(org.netbeans.modules.jakarta.web.beans.xml.Decorators) + */ + public void visit( Decorators decorators ) { + visitBeanElement(decorators); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor#visit(org.netbeans.modules.jakarta.web.beans.xml.Alternatives) + */ + public void visit( Alternatives alternatives ) { + visitBeanElement(alternatives); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor#visit(org.netbeans.modules.jakarta.web.beans.xml.BeanClass) + */ + public void visit( BeanClass clazz ) { + if ( getParent() instanceof Alternatives ){ + visitAlternativesChild(clazz); + } + else if ( getParent() instanceof BeanClassContainer ){ + BeanClassContainer parent = (BeanClassContainer)getParent(); + if ( isAdd() ){ + parent.addBeanClass( getIndex() , clazz ); + } + else if ( isRemove() ){ + parent.removeBeanClass( clazz ); + } + } + else { + assert false; + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor#visit(org.netbeans.modules.jakarta.web.beans.xml.Stereotype) + */ + public void visit( Stereotype stereotype ) { + visitAlternativesChild(stereotype); + } + + private void visitAlternativesChild( AlternativeElement element ) { + assert getParent() instanceof Alternatives; + Alternatives alternatives = (Alternatives)getParent(); + if ( isAdd() ){ + alternatives.addElement( getIndex() , element ); + } + else if ( isRemove() ){ + alternatives.removeElement( element ); + } + } + + private void visitBeanElement( BeansElement element ) { + assert getParent() instanceof Beans; + Beans beans = (Beans)getParent(); + if ( isAdd() ){ + beans.addElement( getIndex() , element ); + } + else if ( isRemove() ){ + beans.removeElement( element ); + } + } + + private boolean isAdd() { + return getOperation() == Operation.ADD; + } + + private boolean isRemove() { + return getOperation() == Operation.REMOVE; + } + + private WebBeansComponent getParent() { + return myParent; + } + + private int getIndex() { + return myIndex; + } + + private Operation getOperation() { + return myOperation; + } + + private WebBeansComponent myParent; + + private int myIndex; + + private Operation myOperation; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/WebBeansComponentBuildVisitor.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/WebBeansComponentBuildVisitor.java new file mode 100644 index 000000000000..37648d727ddb --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/WebBeansComponentBuildVisitor.java @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml.impl; + +import javax.xml.namespace.QName; + +import org.netbeans.modules.jakarta.web.beans.xml.Alternatives; +import org.netbeans.modules.jakarta.web.beans.xml.BeanClass; +import org.netbeans.modules.jakarta.web.beans.xml.BeanClassContainer; +import org.netbeans.modules.jakarta.web.beans.xml.Beans; +import org.netbeans.modules.jakarta.web.beans.xml.Decorators; +import org.netbeans.modules.jakarta.web.beans.xml.Interceptors; +import org.netbeans.modules.jakarta.web.beans.xml.Stereotype; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor; +import org.netbeans.modules.xml.xam.dom.AbstractDocumentComponent; +import org.w3c.dom.Element; + + +/** + * @author ads + * + */ +class WebBeansComponentBuildVisitor implements WebBeansVisitor { + + WebBeansComponentBuildVisitor( WebBeansModelImpl model ) { + myModel = model; + } + + public void init() { + myResult = null; + myElement = null; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor#visit(org.netbeans.modules.jakarta.web.beans.xml.Beans) + */ + public void visit( Beans beans ) { + if ( isAcceptable( WebBeansElements.INTERCEPTORS)){ + setResult( new InterceptorsImpl(getModel() , getElement())); + } + else if (isAcceptable( WebBeansElements.DECORATORS )){ + setResult( new DecoratorsImpl(getModel(), getElement())); + } + else if (isAcceptable( WebBeansElements.ALTERNATIVES)){ + setResult( new AlternativesImpl(getModel(), getElement())); + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor#visit(org.netbeans.modules.jakarta.web.beans.xml.Interceptors) + */ + public void visit( Interceptors interceptors ) { + visitClassContainer( interceptors ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor#visit(org.netbeans.modules.jakarta.web.beans.xml.Decorators) + */ + public void visit( Decorators decorators ) { + visitClassContainer( decorators ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor#visit(org.netbeans.modules.jakarta.web.beans.xml.Alternatives) + */ + public void visit( Alternatives alternatives ) { + if ( isAcceptable( WebBeansElements.CLASS)){ + setResult( new BeanClassImpl(getModel(), getElement())); + } + else if ( isAcceptable( WebBeansElements.STEREOTYPE )){ + setResult( new StereotypeImpl( getModel(), getElement())); + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor#visit(org.netbeans.modules.jakarta.web.beans.xml.BeanClass) + */ + public void visit( BeanClass clazz ) { + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansVisitor#visit(org.netbeans.modules.jakarta.web.beans.xml.Stereotype) + */ + public void visit( Stereotype stereotype ) { + } + + WebBeansComponent create( WebBeansComponent context, Element element ) + { + QName qName = AbstractDocumentComponent.getQName(element); + if ( !(WebBeansComponent.WEB_BEANS_NAMESPACE.equals( + qName.getNamespaceURI() ) || + WebBeansComponent.WEB_BEANS_NAMESPACE_OLD.equals( + qName.getNamespaceURI() ))) + { + return null; + } + if ( context == null ){ + return new BeansImpl( getModel() , element ); + } + else { + myElement = element; + context.accept( this ); + } + return myResult; + } + + + private void visitClassContainer( BeanClassContainer container ) { + if ( isAcceptable( WebBeansElements.CLASS)){ + setResult( new BeanClassImpl(getModel(), getElement())); + } + } + + private WebBeansModelImpl getModel(){ + return myModel; + } + + private void setResult( WebBeansComponent component ) { + myResult = component; + } + + private boolean isAcceptable( WebBeansElements elements ) { + return elements.getName().equals( getLocalName() ); + } + + private String getLocalName() { + return getElement().getLocalName(); + } + + private Element getElement(){ + return myElement; + } + + private WebBeansComponent myResult; + + private Element myElement; + + private WebBeansModelImpl myModel; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/WebBeansComponentFactoryImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/WebBeansComponentFactoryImpl.java new file mode 100644 index 000000000000..68e101b3ec66 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/WebBeansComponentFactoryImpl.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml.impl; + +import org.netbeans.modules.jakarta.web.beans.xml.Alternatives; +import org.netbeans.modules.jakarta.web.beans.xml.BeanClass; +import org.netbeans.modules.jakarta.web.beans.xml.Beans; +import org.netbeans.modules.jakarta.web.beans.xml.Decorators; +import org.netbeans.modules.jakarta.web.beans.xml.Interceptors; +import org.netbeans.modules.jakarta.web.beans.xml.Stereotype; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponentFactory; +import org.w3c.dom.Element; + + +/** + * @author ads + * + */ +class WebBeansComponentFactoryImpl implements WebBeansComponentFactory { + + WebBeansComponentFactoryImpl( WebBeansModelImpl model ){ + myModel = model; + myBuilder = new ThreadLocal(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponentFactory#createBeans() + */ + public Beans createBeans() { + return new BeansImpl( getModel()); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponentFactory#createComponent(org.w3c.dom.Element, org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent) + */ + public WebBeansComponent createComponent( Element element, + WebBeansComponent context ) + { + WebBeansComponentBuildVisitor visitor = getBuilder(); + return visitor.create( context , element ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponentFactory#createAlternatives() + */ + public Alternatives createAlternatives() { + return new AlternativesImpl(getModel()); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponentFactory#createBeanClass() + */ + public BeanClass createBeanClass() { + return new BeanClassImpl( getModel()); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponentFactory#createDecorators() + */ + public Decorators createDecorators() { + return new DecoratorsImpl( getModel()); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponentFactory#createInterceptors() + */ + public Interceptors createInterceptors() { + return new InterceptorsImpl(getModel()); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponentFactory#createStereotype() + */ + public Stereotype createStereotype() { + return new StereotypeImpl(getModel()); + } + + private WebBeansModelImpl getModel(){ + return myModel; + } + + private WebBeansComponentBuildVisitor getBuilder(){ + WebBeansComponentBuildVisitor visitor = myBuilder.get(); + if ( visitor == null ){ + visitor = new WebBeansComponentBuildVisitor( getModel() ); + myBuilder.set( visitor ); + } + visitor.init(); + return visitor; + } + + private WebBeansModelImpl myModel; + + private ThreadLocal myBuilder; + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/WebBeansComponentImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/WebBeansComponentImpl.java new file mode 100644 index 000000000000..eb00aeaefa5c --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/WebBeansComponentImpl.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml.impl; + +import java.util.List; + +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent; +import org.netbeans.modules.xml.xam.dom.AbstractDocumentComponent; +import org.netbeans.modules.xml.xam.dom.Attribute; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * @author ads + * + */ +abstract class WebBeansComponentImpl extends + AbstractDocumentComponent implements WebBeansComponent +{ + WebBeansComponentImpl( WebBeansModelImpl model, Element e ) { + super(model, e); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.xml.xam.dom.AbstractDocumentComponent#getModel() + */ + @Override + public WebBeansModelImpl getModel() { + return (WebBeansModelImpl)super.getModel(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.xml.xam.dom.AbstractDocumentComponent#getAttributeValueOf(org.netbeans.modules.xml.xam.dom.Attribute, java.lang.String) + */ + @Override + protected Object getAttributeValueOf( Attribute attr, String stringValue ) { + return null; + } + + protected static Element createNewElement(String name, WebBeansModelImpl model){ + String ns = WebBeansComponent.WEB_BEANS_NAMESPACE; + if(model.getRootComponent() instanceof AbstractDocumentComponent) { + ns = ((AbstractDocumentComponent)model.getRootComponent()).getQName().getNamespaceURI(); + } + return model.getDocument().createElementNS( ns, name ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.xml.xam.dom.AbstractDocumentComponent#populateChildren(java.util.List) + */ + @Override + protected void populateChildren( List children ) { + NodeList nl = getPeer().getChildNodes(); + if (nl != null) { + for (int i = 0; i < nl.getLength(); i++) { + Node n = nl.item(i); + if (n instanceof Element) { + WebBeansComponent comp = getModel().getFactory().createComponent((Element) n, this); + if (comp != null) { + children.add(comp); + } + } + } + } + } + +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/WebBeansElements.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/WebBeansElements.java new file mode 100644 index 000000000000..f2fc01813b37 --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/WebBeansElements.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml.impl; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + +import javax.xml.namespace.QName; + +import org.netbeans.modules.jakarta.web.beans.xml.Alternatives; +import org.netbeans.modules.jakarta.web.beans.xml.BeanClass; +import org.netbeans.modules.jakarta.web.beans.xml.Decorators; +import org.netbeans.modules.jakarta.web.beans.xml.Interceptors; +import org.netbeans.modules.jakarta.web.beans.xml.Stereotype; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent; +import static org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent.WEB_BEANS_NAMESPACE_OLD; +import org.netbeans.modules.xml.xam.dom.AbstractDocumentComponent; + + +/** + * @author ads + * + */ +public enum WebBeansElements { + + BEANS("beans"), + DECORATORS(Decorators.DECORATORS), + INTERCEPTORS( Interceptors.INTERCEPTORS), + ALTERNATIVES( Alternatives.ALTERNATIVES), + CLASS( BeanClass.CLASS), + STEREOTYPE( Stereotype.STEREOTYPE); + + WebBeansElements( String name ){ + myName = name; + } + + public String getName() { + return myName; + } + + public QName getQName(WebBeansModelImpl model) { + String ns = WebBeansComponent.WEB_BEANS_NAMESPACE; + if( model.getRootComponent() instanceof AbstractDocumentComponent) { + ns = ((AbstractDocumentComponent)model.getRootComponent()).getQName().getNamespaceURI(); + } + return new QName( ns, getName() ); + } + + + public static Set allQNames(WebBeansModelImpl model) { + if ( myQNames.get() == null ) { + Set set = new HashSet( values().length ); + for (WebBeansElements element : values() ) { + set.add( element.getQName(model) ); + } + myQNames.compareAndSet( null, set ); + } + return myQNames.get(); + } + + private String myName; + + private static AtomicReference> myQNames = + new AtomicReference>(); +} diff --git a/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/WebBeansModelImpl.java b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/WebBeansModelImpl.java new file mode 100644 index 000000000000..b1f8d9bd676f --- /dev/null +++ b/enterprise/jakarta.web.beans/src/org/netbeans/modules/jakarta/web/beans/xml/impl/WebBeansModelImpl.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xml.impl; + +import java.util.Set; + +import javax.xml.namespace.QName; + +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansComponent; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansModel; +import org.netbeans.modules.xml.xam.ComponentUpdater; +import org.netbeans.modules.xml.xam.ModelSource; +import org.netbeans.modules.xml.xam.dom.AbstractDocumentModel; +import org.w3c.dom.Element; + + +/** + * @author ads + * + */ +public class WebBeansModelImpl extends AbstractDocumentModel + implements WebBeansModel +{ + + public WebBeansModelImpl( ModelSource source ) { + super(source); + myFactory = new WebBeansComponentFactoryImpl( this ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.xml.xam.dom.AbstractDocumentModel#createRootComponent(org.w3c.dom.Element) + */ + @Override + public WebBeansComponent createRootComponent( Element root ) { + BeansImpl beans = (BeansImpl)getFactory().createComponent( root, null); + if ( beans!= null ){ + myRoot = beans; + } + else { + return null; + } + return getBeans(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.xml.xam.dom.AbstractDocumentModel#getComponentUpdater() + */ + @Override + public ComponentUpdater getComponentUpdater() { + if ( mySyncUpdateVisitor== null ){ + mySyncUpdateVisitor = new SyncUpdateVisitor(); + } + return mySyncUpdateVisitor; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.xml.xam.dom.DocumentModel#createComponent(org.netbeans.modules.xml.xam.dom.DocumentComponent, org.w3c.dom.Element) + */ + public WebBeansComponent createComponent( WebBeansComponent parent, + Element element ) + { + return getFactory().createComponent(element, parent ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.xml.xam.dom.DocumentModel#getRootComponent() + */ + public WebBeansComponent getRootComponent() { + if(myRoot == null) { + refresh(); + } + return myRoot; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansModel#getBeans() + */ + public BeansImpl getBeans() { + return (BeansImpl)getRootComponent(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.xml.WebBeansModel#getFactory() + */ + public WebBeansComponentFactoryImpl getFactory() { + return myFactory; + } + + public Set getQNames() { + return WebBeansElements.allQNames(this); + } + + private BeansImpl myRoot; + + private SyncUpdateVisitor mySyncUpdateVisitor; + + private WebBeansComponentFactoryImpl myFactory; +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/BaseAnalisysTestCase.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/BaseAnalisysTestCase.java new file mode 100644 index 000000000000..df6f443ad9a1 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/BaseAnalisysTestCase.java @@ -0,0 +1,349 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.java.classpath.GlobalPathRegistry; +import org.netbeans.api.java.source.ClasspathInfo; +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.JavaSource; +import org.netbeans.api.java.source.JavaSource.Phase; +import org.netbeans.api.java.source.Task; +import org.netbeans.modules.j2ee.metadata.model.support.JavaSourceTestCase; +import org.netbeans.modules.parsing.api.indexing.IndexingManager; +import org.netbeans.modules.jakarta.web.beans.testutilities.CdiTestUtilities; +import org.openide.filesystems.FileObject; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; + + +/** + * @author ads + * + */ +public abstract class BaseAnalisysTestCase extends JavaSourceTestCase { + + protected static final ResultProcessor NO_ERRORS_PROCESSOR = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + Set elements = result.getErrors().keySet(); + String msg = ""; + if ( !elements.isEmpty()) { + msg = result.getErrors().values().iterator().next(); + } + assertTrue( "Expected no errors, but found :" +msg , elements.isEmpty() ); + elements = result.getWarings().keySet(); + if ( !elements.isEmpty()) { + msg = result.getWarings().values().iterator().next(); + } + assertTrue( "Expected no warnings, but found :" +msg , elements.isEmpty() ); + } + + }; + + protected static final ResultProcessor WARNINGS_PROCESSOR = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + Set elements = result.getErrors().keySet(); + String msg = ""; + if ( !elements.isEmpty()) { + msg = result.getErrors().values().iterator().next(); + } + assertTrue( "Expected no errors, but found :" +msg , elements.isEmpty() ); + } + + }; + + public BaseAnalisysTestCase( String testName ) { + super(testName); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.j2ee.metadata.model.support.JavaSourceTestCase#setUp() + */ + @Override + protected void setUp() throws Exception { + super.setUp(); + GlobalPathRegistry.getDefault().register(ClassPath.SOURCE, + new ClassPath[] { ClassPath.getClassPath(srcFO, ClassPath.SOURCE) }); + GlobalPathRegistry.getDefault().register(ClassPath.BOOT, + new ClassPath[] { bootCP }); + myClassPathInfo = ClasspathInfo.create(srcFO); + myUtilities = new CdiTestUtilities( srcFO ); + myUtilities.initAnnotations(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.j2ee.metadata.model.support.JavaSourceTestCase#tearDown() + */ + @Override + protected void tearDown() { + } + + protected void runAnalysis( FileObject fileObject , + final ResultProcessor processor ) throws IOException + { + IndexingManager.getDefault().refreshIndexAndWait(srcFO.getURL(), null); + JavaSource js = JavaSource.create(myClassPathInfo, fileObject ); + final AbstractAnalysisTask task = createTask(); + js.runWhenScanFinished( new Task() { + + @Override + public void run( CompilationController controller ) throws Exception { + controller.toPhase( Phase.ELEMENTS_RESOLVED ); + + task.run( controller ); + processor.process((TestProblems)task.getResult()); + } + }, true); + } + + protected CdiTestUtilities getUtilities(){ + return myUtilities; + } + + protected void checkFieldElement(TestProblems result , String enclosingClass, + String expectedName ) + { + checkFieldElement(result, enclosingClass, expectedName, false ); + } + + protected void checkFieldElement(TestProblems result , String enclosingClass, + String expectedName , boolean checkOnlyFields ) + { + checkElement(result, enclosingClass, expectedName, VariableElement.class, + checkOnlyFields); + } + + protected void checkMethodElement(TestProblems result , String enclosingClass, + String expectedName , boolean checkOnlyFields) + { + checkElement(result, enclosingClass, expectedName, ExecutableElement.class, + checkOnlyFields); + } + + protected void checkMethodElement(Map map , String enclosingClass, + String expectedName ) + { + ElementMatcher matcher = new SimpleNameMatcher( expectedName ); + checkElement(map, enclosingClass, matcher, ExecutableElement.class, + false); + } + + protected void checkFieldElement(Map map , String enclosingClass, + String expectedName ) + { + ElementMatcher matcher = new SimpleNameMatcher( expectedName ); + checkElement(map, enclosingClass, matcher, VariableElement.class, + false); + } + + protected void checkMethodElement(TestProblems result , String enclosingClass, + String expectedName ) + { + checkMethodElement(result, enclosingClass, expectedName, false ); + } + + protected void checkCtor(TestProblems result , String enclosingClass) + { + ElementMatcher matcher = new CtorMatcher(); + checkElement(result, enclosingClass, matcher, ExecutableElement.class, false); + } + + protected void checkElement(TestProblems result , String enclosingClass, + String expectedName , Class elementClass, boolean checkOnlyFields ) + { + ElementMatcher matcher = new SimpleNameMatcher( expectedName ); + checkElement(result, enclosingClass, matcher, elementClass, checkOnlyFields); + } + + protected void checkElement(TestProblems result , String enclosingClass, + ElementMatcher matcher, Class elementClass, boolean checkOnlyFields ) + { + checkElement(result.getErrors(), enclosingClass, matcher, elementClass, + checkOnlyFields); + } + + protected void checkElement(Map map , String enclosingClass, + ElementMatcher matcher, Class elementClass, boolean checkOnlyFields ) + { + Set elements = map.keySet(); + Set classElements = new HashSet(); + TypeElement enclosingClazz = null; + for( Element element : elements ){ + Element enclosingElement = element.getEnclosingElement(); + TypeElement clazz = null; + boolean forAdd = false ; + if ( enclosingElement instanceof TypeElement ){ + forAdd = true; + clazz = (TypeElement) enclosingElement; + } + else if ( element instanceof TypeElement ){ + if ( !checkOnlyFields ){ + forAdd = true; + } + clazz = (TypeElement)element; + } + else { + assertTrue("Found element which parent is not a type definition " + + "and is not a definition itself ", false); + } + if ( forAdd && clazz.getQualifiedName().contentEquals( enclosingClass )){ + enclosingClazz = clazz; + //System.out.println( "Found element : "+element); + classElements.add( element ); + } + } + assertNotNull("Expected enclosing class doesn't contain errors", enclosingClazz ); + assertEquals( "Expected exactly one error element", 1 , classElements.size()); + Element element = classElements.iterator().next(); + assertTrue( "Element has a class "+element.getClass(), + elementClass.isAssignableFrom( element.getClass() ) ); + boolean match = matcher.matches( element ); + if ( !match ){ + assertTrue( matcher.getMessage(), match); + } + } + + protected void checkParamElement(TestProblems result , String enclosingClass, + String methodName , String paramName ) + { + checkParamElement(result.getErrors(), enclosingClass, methodName, paramName); + } + + protected void checkParamElement(Map map, String enclosingClass, + String methodName , String paramName ) + { + Set elements = map.keySet(); + Set classElements = new HashSet(); + TypeElement enclosingClazz = null; + ExecutableElement method = null; + for( Element element : elements ){ + Element enclosingElement = element.getEnclosingElement(); + TypeElement clazz = null; + ExecutableElement methodElement = null; + boolean forAdd = false ; + if ( enclosingElement instanceof TypeElement ){ + forAdd = true; + clazz = (TypeElement) enclosingElement; + } + else if ( element instanceof TypeElement ){ + clazz = (TypeElement)element; + } + else if ( enclosingElement instanceof ExecutableElement ) { + forAdd = true; + methodElement = (ExecutableElement)enclosingElement; + } + else { + assertTrue("Found element which parent is not a type definition, " + + "not a definition itself and not method", false); + } + if ( forAdd && methodElement != null && + methodElement.getSimpleName().contentEquals( methodName )) + { + method = methodElement; + enclosingClazz = (TypeElement)method.getEnclosingElement(); + classElements.add( element ); + } + } + assertNotNull("Expected enclosing class doesn't contain errors", enclosingClazz ); + assertNotNull("Expected enclosing method doesn't contain errors", method ); + assertEquals( "Expected exactly one error element", 1 , classElements.size()); + Element element = classElements.iterator().next(); + assertEquals(paramName, element.getSimpleName().toString()); + } + + protected void checkTypeElement( TestProblems result , String expectedName ){ + checkTypeElement(result.getErrors(), expectedName); + assertEquals( "Found unexpected warnings" , 0, result.getWarings().size() ); + } + + protected void checkTypeElement( Map map, String expectedName ){ + Set elements = map.keySet(); + if ( elements.size() > 1 ){ + for( Element element : elements ){ + System.out.println( "Found element : "+element.toString()); + } + } + assertEquals( "Expected exactly one error element", 1 , elements.size()); + Element element = elements.iterator().next(); + assertTrue( element instanceof TypeElement ); + String fqn = ((TypeElement)element).getQualifiedName().toString(); + assertEquals(expectedName, fqn); + } + + interface ElementMatcher { + boolean matches(Element element); + String getMessage(); + } + + class SimpleNameMatcher implements ElementMatcher { + + SimpleNameMatcher( String simpleName ){ + myName = simpleName; + } + + public boolean matches(Element element){ + myMessage = "Found "+element.getSimpleName()+" element, expected "+myName; + return myName.contentEquals( element.getSimpleName()); + } + + public String getMessage() { + return myMessage; + } + + private String myName; + private String myMessage; + } + + class CtorMatcher implements ElementMatcher { + + public boolean matches(Element element){ + myKind = element.getKind(); + return myKind== ElementKind.CONSTRUCTOR; + } + + public String getMessage() { + return "Found element has "+myKind+" , not CTOR"; + } + + private ElementKind myKind; + } + + protected abstract AbstractAnalysisTask createTask(); + + private ClasspathInfo myClassPathInfo; + private CdiTestUtilities myUtilities; + + protected static interface ResultProcessor { + void process ( TestProblems result ); + } + +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiAnalysisTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiAnalysisTest.java new file mode 100644 index 000000000000..c848dc36da3d --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiAnalysisTest.java @@ -0,0 +1,1519 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; + +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +public class CdiAnalysisTest extends BaseAnalisysTestCase { + + /** + * @param testName + */ + public CdiAnalysisTest( String testName ) { + super(testName); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.BaseAnalisysTestCase#createTask() + */ + @Override + protected CdiAnalysisTestTask createTask() { + return new CdiAnalysisTestTask(); + } + + /* + * TypedClassAnalizer + */ + public void testTypedClass() throws IOException{ + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import java.util.List; "+ + "import jakarta.enterprise.inject.Typed; "+ + "@Typed({List.class}) "+ + " public class Clazz { "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.enterprise.inject.Typed; "+ + "@Typed({Comparable.class}) "+ + " public class Clazz1 implements Comparable { "+ + " public int comapreTo( String str ) {"+ + " return 0; "+ + " }"+ + "}"); + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Clazz"); + } + + }; + runAnalysis(errorFile , processor); + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * AnnotationsAnalyzer(ClassAnalyzer) checkDecoratorInterceptor + */ + public void testAnnotationsDecoratorInterceptor() throws IOException{ + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.decorator.Decorator; "+ + "import jakarta.interceptor.Interceptor; "+ + "@Decorator "+ + "@Interceptor "+ + " public class Clazz { "+ + "}"); + + FileObject goodFile =TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.interceptor.Interceptor; "+ + "@Interceptor "+ + " public class Clazz1 { "+ + "}"); + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Clazz"); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * AnnotationsAnalyzer(ClassAnalyzer) checkDelegateInjectionPoint + */ + public void testDecoratorDelegate() throws IOException{ + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import java.util.List; "+ + "import jakarta.decorator.Decorator; "+ + "import jakarta.inject.Inject; "+ + "@Decorator "+ + " public class Clazz { "+ + " @Inject int injectionPoint; "+ + "}"); + + /* + * Create a good one class file + */ + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.decorator.Decorator; "+ + "import jakarta.decorator.Delegate; "+ + "@Decorator "+ + " public class Clazz1 { "+ + " public Clazz1( @Delegate Object arg ){ "+ + " }"+ + "}"); + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Clazz"); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * AnnotationsAnalyzer(ClassAnalyzer) checkProducerFields + */ + public void testDecoratorProducerField() throws IOException{ + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.decorator.Decorator; "+ + "import jakarta.enterprise.inject.Produces; "+ + "@Decorator "+ + " public class Clazz { "+ + " @Produces int production; "+ + "}"); + + /* + * Create a good one class file + */ + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.decorator.Decorator; "+ + "import jakarta.decorator.Delegate; "+ + "import jakarta.inject.Inject; "+ + "@Decorator "+ + " public class Clazz1 { "+ + " @Inject @Delegate Object injection; "+ + "}"); + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Clazz"); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * AnnotationsAnalyzer(ClassAnalyzer) checkMethods + */ + public void testInterceptorMethods() throws IOException{ + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.interceptor.Interceptor; "+ + "import jakarta.enterprise.inject.Produces; "+ + "@Interceptor "+ + " public class Clazz { "+ + " @Produces int production(){ return 0 } ; "+ + "}"); + + /* + * Create a good one class file + */ + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.interceptor.Interceptor; "+ + "import jakarta.enterprise.inject.Produces; "+ + "@Interceptor "+ + " public class Clazz1 { "+ + " int method(){ return 0;} "+ + "}"); + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Clazz"); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * AnnotationsAnalyzer(ClassAnalyzer) checkSession + */ + public void testInterceptorSessionBeans() throws IOException{ + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.interceptor.Interceptor; "+ + "import jakarta.ejb.Singleton; "+ + "@Interceptor "+ + "@Singleton "+ + " public class Clazz { "+ + "}"); + + /* + * Create a good one class file + */ + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.interceptor.Interceptor; "+ + "@Interceptor "+ + " public class Clazz1 { "+ + "}"); + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Clazz"); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * AnnotationsAnalyzer(ClassAnalyzer) checkNamed , checkAlternatives, checkSpecializes + */ + public void testInterceptorAlternativeNamed() throws IOException{ + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.interceptor.Interceptor; "+ + " import jakarta.inject.Named; "+ + "@Named "+ + "@Interceptor "+ + " public class Clazz { "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.interceptor.Interceptor; "+ + "import jakarta.enterprise.inject.Alternative; "+ + "@Alternative "+ + "@Interceptor "+ + " public class Clazz1 { "+ + "}"); + + FileObject errorFile2 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + "import jakarta.interceptor.Interceptor; "+ + "import jakarta.enterprise.inject.Specializes; "+ + "@Interceptor "+ + "@Specializes "+ + " public class Clazz2 { "+ + "}"); + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result.getWarings(), "foo.Clazz"); + assertEquals( 0, result.getErrors().size()); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result.getWarings(), "foo.Clazz1"); + assertEquals( 0, result.getErrors().size()); + } + + }; + runAnalysis(errorFile1 , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result.getWarings(), "foo.Clazz2"); + assertEquals( 0, result.getErrors().size()); + } + + }; + runAnalysis(errorFile2 , processor); + } + + /* + * CtorsAnalyzer + */ + public void testInitializerCtors() throws IOException{ + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jajakartavax.inject.Inject; "+ + " public class Clazz { "+ + " @Inject public Clazz( int i){} "+ + " @Inject public Clazz( String str ){} "+ + "}"); + + /* + * Create a good one class file + */ + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " public class Clazz1 { "+ + " @Inject public Clazz1( int i){} "+ + " public Clazz1( Stirng str ){} "+ + "}"); + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Clazz"); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * TypedFieldAnalyzer + */ + public void testTypedField() throws IOException{ + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import java.util.List; "+ + "import jakarta.enterprise.inject.Typed; "+ + " public class Clazz { "+ + " @Typed({List.class}) Object field; "+ + " int field1; "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.enterprise.inject.Typed; "+ + "import java.util.List; "+ + "import java.util.Collection; "+ + " public class Clazz1 { "+ + " @Typed({Collection.class}) List field; "+ + " int field1; "+ + "}"); + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result, "foo.Clazz", "field"); + } + + }; + runAnalysis(errorFile , processor); + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * DelegateFieldAnalizer + */ + public void testDelegateField() throws IOException{ + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface.java", + "package foo; " + + " public interface Iface { "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.decorator.Decorator; "+ + "import jakarta.decorator.Delegate; "+ + "import jakarta.inject.Inject; "+ + " @Decorator "+ + " public class Clazz implements Iface { "+ + " @Inject @Delegate Iface delegateInjection; "+ + " int field1; "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.decorator.Decorator; "+ + "import jakarta.decorator.Delegate; "+ + " @Decorator "+ + " public class Clazz1 implements Iface { "+ + " @Delegate Iface delegateInjection; "+ + " int field1; "+ + "}"); + + FileObject errorFile2 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + "import jakarta.decorator.Decorator; "+ + "import jakarta.decorator.Delegate; "+ + " public class Clazz2 implements Iface { "+ + " @Inject @Delegate Iface delegateInjection; "+ + " int field1; "+ + "}"); + + FileObject errorFile3 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz3.java", + "package foo; " + + "import jakarta.decorator.Decorator; "+ + "import jakarta.decorator.Delegate; "+ + "import jakarta.inject.Inject; "+ + " @Decorator "+ + " public class Clazz3 implements Iface { "+ + " @Inject @Delegate Object delegateInjection; "+ + " int field1; "+ + "}"); + + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result, "foo.Clazz1", "delegateInjection", + true); + Set elements = result.getErrors().keySet(); + assertEquals( "Exactly two errors should be detected" , + 2, elements.size()); + boolean clazzFound = false; + for (Element element : elements) { + if ( element instanceof TypeElement ){ + String fqn = ((TypeElement)element). + getQualifiedName().toString(); + if ( fqn.equals("foo.Clazz1")){ + clazzFound = true; + } + } + } + assertTrue("foo.Clazz1 should be marked with an error ",clazzFound); + } + + }; + runAnalysis(errorFile1 , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result, "foo.Clazz2", "delegateInjection"); + } + + }; + runAnalysis(errorFile2 , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result, "foo.Clazz3", "delegateInjection"); + } + + }; + runAnalysis(errorFile3 , processor); + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * ProducerFieldAnalyzer : checkSessionBean + */ + public void testProductionFieldInSession() throws IOException{ + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.enterprise.inject.Produces; "+ + "import jakarta.ejb.Singleton; "+ + "@Singleton "+ + " public class Clazz { "+ + " @Produces int production; "+ + " int field1; "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.enterprise.inject.Produces; "+ + "import jakarta.ejb.Singleton; "+ + "@Singleton "+ + " public class Clazz1 { "+ + " static @Produces int production; "+ + " int field1; "+ + "}"); + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result, "foo.Clazz", "production"); + } + + }; + runAnalysis(errorFile , processor); + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * ProducerFieldAnalyzer : checkType + */ + public void testProductionFieldType() throws IOException{ + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.enterprise.inject.Produces; "+ + " public class Clazz { "+ + " static @Produces Class production; "+ + " int field1; "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.enterprise.inject.Produces; "+ + " public class Clazz1 { "+ + " @Produces T production; "+ + " int field1; "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + "import jakarta.enterprise.inject.Produces; "+ + " public class Clazz2 { "+ + " @Produces Class production; "+ + " int field1; "+ + "}"); + + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result, "foo.Clazz1", "production"); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result, "foo.Clazz2", "production"); + } + + }; + runAnalysis(errorFile1 , processor); + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * TypedMethodAnalyzer + */ + public void testTypedMethod() throws IOException{ + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import java.util.List; "+ + "import jakarta.enterprise.inject.Typed; "+ + " public class Clazz { "+ + " @Typed({List.class}) Object method(){ return null; } "+ + " int operation(){ return 0; } "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.enterprise.inject.Typed; "+ + "import java.util.List; "+ + "import java.util.Collection; "+ + " public class Clazz1 { "+ + " @Typed({Collection.class}) List method(){ return null; }; "+ + " int operation(){ return 0; } "+ + "}"); + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz", "method"); + } + + }; + runAnalysis(errorFile , processor); + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * AnnotationsAnalyzer : combinations of various CDI annotations: inject, producer, observer, disposes + */ + public void testMethodAnnotations() throws IOException { + /* + * Create a good one class file + */ + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, + "foo/Clazz.java", "package foo; " + + "import jakarta.inject.Inject; " + + "import jakarta.enterprise.event.Observes; " + + "import jakarta.enterprise.inject.Produces; " + +" import jakarta.enterprise.inject.Disposes; " + + " public class Clazz { " + + " @Inject int initializer( int arg ) { return 0; } " + + " @Produces String production(){return null; } ; " + + " void observer( @Observes String event ){} ; " + + " void disposer( @Disposes int arg ){} " + + "}"); + + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, + "foo/Clazz1.java", + "package foo; " + + "import jakarta.inject.Inject; " + + "import jakarta.enterprise.inject.Produces; " + + " public class Clazz1 { " + + " @Inject @Produces int badProduction( int arg ){ return 0; } "+ + " void method(){} " + + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, + "foo/Clazz2.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; " + + "import jakarta.enterprise.inject.Produces; " + + " public class Clazz2 { " + + " @Produces int badProduction( @Observes String event) { return 0; }"+ + " void method(){} " + + "}"); + + FileObject errorFile2 = TestUtilities.copyStringToFileObject(srcFO, + "foo/Clazz3.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; " + +" import jakarta.enterprise.inject.Disposes; " + + " public class Clazz3 { " + + " int badObserver( @Disposes @Observes String event) { return 0; }"+ + " void method(){} " + + "}"); + + + ResultProcessor processor = new ResultProcessor() { + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz1", "badProduction"); + } + + }; + runAnalysis(errorFile, processor); + + processor = new ResultProcessor() { + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz2", "badProduction"); + } + + }; + runAnalysis(errorFile1, processor); + + processor = new ResultProcessor() { + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz3", "badObserver"); + } + + }; + runAnalysis(errorFile2, processor); + + + runAnalysis(goodFile, NO_ERRORS_PROCESSOR); + } + + /* + * AnnotationsAnalyzer: checkAbstractMethod + */ + public void testAbstractMethod() throws IOException { + /* + * Create a good one class file + */ + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, + "foo/Clazz.java", "package foo; " + + "import jakarta.inject.Inject; " + + "import jakarta.enterprise.inject.Produces; " + + " import jakarta.enterprise.inject.Disposes; " + + " public class Clazz { " + + " @Produces String production(){return null; } ; " + + " void disposer( @Disposes int arg ){} " + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, + "foo/Clazz1.java", "package foo; " + + "import jakarta.inject.Inject; " + + "import jakarta.enterprise.inject.Produces; " + + " public class Clazz1 { " + + " @Produces abstract int badProduction( int arg ); " + + " void method(){} " + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, + "foo/Clazz2.java", "package foo; " + + " import jakarta.enterprise.inject.Disposes; " + + " public class Clazz2 { " + + " abstract int badDisposer( @Disposes String arg);" + + " void method(){} " + "}"); + + ResultProcessor processor = new ResultProcessor() { + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz1", "badProduction"); + } + + }; + runAnalysis(errorFile, processor); + + processor = new ResultProcessor() { + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz2", "badDisposer"); + } + + }; + runAnalysis(errorFile1, processor); + + runAnalysis(goodFile, NO_ERRORS_PROCESSOR); + } + + /* + * AnnotationsAnalyzer: checkBusinessMethod + */ + public void testBusinessAnnotations() throws IOException { + /* + * Create a good one class file + */ + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, + "foo/Clazz.java", "package foo; " + + "import jakarta.inject.Inject; " + + "import jakarta.enterprise.inject.Produces; " + +" import jakarta.enterprise.inject.Disposes; " + + "import jakarta.enterprise.event.Observes; " + + "import jakarta.ejb.Stateful; " + + " @Stateful " + + " public class Clazz { " + + " public @Produces String production(){return null; } ; " + + " public void disposer( @Disposes int arg ){} " + + " public void observer( @Observes String event ){} " + + "}"); + + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, + "foo/Clazz1.java", + "package foo; " + + "import jakarta.ejb.Stateful; " + + "import jakarta.enterprise.inject.Produces; " + + " @Stateful " + + " public class Clazz1 { " + + " @Produces int notBusiness( int arg ){ return 0;} "+ + " void method(){} " + + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, + "foo/Clazz2.java", + "package foo; " + + "import jakarta.ejb.Stateful; " + +" import jakarta.enterprise.inject.Disposes; " + + " @Stateful " + + " public class Clazz2 { " + + " public final void notBusiness( @Disposes String arg){ } "+ + " void method(){} " + + "}"); + + FileObject errorFile2 = TestUtilities.copyStringToFileObject(srcFO, + "foo/Clazz3.java", + "package foo; " + + "import jakarta.ejb.Stateful; " + + "import jakarta.enterprise.event.Observes; " + + "import jakarta.ejb.PostActivate; " + + " @Stateful " + + " public class Clazz3 { " + + " @PostActivate public void lifecycle( @Observes String event){ } "+ + " void method(){} " + + "}"); + + + ResultProcessor processor = new ResultProcessor() { + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz1", "notBusiness"); + } + + }; + runAnalysis(errorFile, processor); + + processor = new ResultProcessor() { + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz2", "notBusiness"); + } + + }; + runAnalysis(errorFile1, processor); + + processor = new ResultProcessor() { + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz3", "lifecycle"); + } + + }; + runAnalysis(errorFile2, processor); + + runAnalysis(goodFile, NO_ERRORS_PROCESSOR); + } + + /* + * AnnotationsAnalyzer: initializers check + */ + public void testInitializers() throws IOException{ + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " public class Clazz { "+ + " @Inject public initMethod( int i){} "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " public class Clazz1 { "+ + " @Inject abstract public void badInit(); "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " public class Clazz2 { "+ + " @Inject static public void badInit() {} "+ + "}"); + + FileObject errorFile2 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz3.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " public class Clazz3 { "+ + " @Inject public void badInit( Class clazz ) {} "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz1", "badInit"); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz2", "badInit"); + } + + }; + runAnalysis(errorFile1 , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz3", "badInit"); + } + + }; + runAnalysis(errorFile2 , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * DelegateMethodAnalyzer: checkMethodDefinition, checkClassDefinition, checkDelegateType + */ + public void testDelegateMethod() throws IOException{ + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface.java", + "package foo; " + + " public interface Iface { "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Decorated.java", + "package foo; " + + " public class Decorated implements Iface { "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.decorator.Delegate; "+ + "import jakarta.decorator.Decorator; "+ + "import jakarta.inject.Inject; "+ + " @Decorator "+ + " public class Clazz implements Iface { "+ + " @Inject public void initMethod( @Delegate Iface obj ){} "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + "import jakarta.decorator.Delegate; "+ + "import jakarta.decorator.Decorator; "+ + " @Decorator "+ + " public class Clazz1 implements Iface { "+ + " public void badDelegate( @Delegate Iface obj ){} "+ + "}"); + + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + "import jakarta.decorator.Delegate; "+ + " public class Clazz2 implements Iface { "+ + " @Inject public void badDelegate( @Delegate Iface obj ){} "+ + "}"); + + FileObject errorFile2 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz3.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + "import jakarta.decorator.Decorator; "+ + "import jakarta.decorator.Delegate; "+ + " @Decorator "+ + " public class Clazz3 implements Iface { "+ + " @Inject public void badDelegate( @Delegate Object clazz ) {} "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + Map errors = result.getErrors(); + boolean classFound = false; + boolean parameterFound = false; + assertEquals( "Expected exactly two error elements" , 2, errors.keySet().size()); + for( Element element : errors.keySet() ){ + if ( element instanceof TypeElement ) { + classFound = ((TypeElement)element).getQualifiedName(). + contentEquals("foo.Clazz1"); + } + else if ( element instanceof VariableElement ){ + parameterFound = element.getSimpleName().contentEquals("obj"); + if ( parameterFound ){ + parameterFound = element.getEnclosingElement().getSimpleName(). + contentEquals("badDelegate"); + } + } + } + assertTrue( "Clazz1 is expected as error element context",classFound ); + assertTrue( "parameter 'obj' of method 'badDelegate' is expected " + + "as error element context",classFound ); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkParamElement(result, "foo.Clazz2", "badDelegate", "obj"); + } + + }; + runAnalysis(errorFile1 , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkParamElement(result, "foo.Clazz3", "badDelegate", "clazz"); + } + + }; + runAnalysis(errorFile2 , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * ProducerMethodAnalyzer : checkType, checkSpecializes + */ + public void testProducerMethod() throws IOException{ + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.enterprise.inject.Produces; "+ + " public class Clazz { "+ + " static @Produces Class productionMethod(){ return null; } "+ + " void operation(){} "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.enterprise.inject.Produces; "+ + " public class Clazz1 { "+ + " @Produces T productionMethod(){ return null; } "+ + " void operation(){} "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + "import jakarta.enterprise.inject.Produces; "+ + " public class Clazz2 { "+ + " @Produces Class productionMethod(){ return null; } "+ + " void operation(){} "+ + "}"); + + FileObject errorFile2 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz3.java", + "package foo; " + + "import jakarta.enterprise.inject.Produces; "+ + "import jakarta.enterprise.inject.Specializes; "+ + " public class Clazz3 { "+ + " static @Specializes @Produces String productionMethod(){ return null; } "+ + " @Produces String productionMethod1(){ return null; } "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperClass.java", + "package foo; " + + "import jakarta.enterprise.inject.Produces; "+ + " public class SuperClass { "+ + " String nonProduction(){ return null; } "+ + " @Produces String superProduction(){ return null; } "+ + "}"); + + FileObject errorFile3 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz4.java", + "package foo; " + + "import jakarta.enterprise.inject.Produces; "+ + "import jakarta.enterprise.inject.Specializes; "+ + " public class Clazz4 extends SuperClass{ "+ + " @Specializes @Produces String nonProduction(){ return null; } "+ + " @Specializes @Produces String superProduction(){ return null; } "+ + "}"); + + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz1", "productionMethod"); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz2", "productionMethod"); + } + + }; + runAnalysis(errorFile1 , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz3", "productionMethod"); + } + + }; + runAnalysis(errorFile2 , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz4", "nonProduction"); + } + + }; + runAnalysis(errorFile3 , processor); + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * org.netbeans.modules.jakarta.web.beans.analysis.analyzer.CtorAnalyzer + */ + public void testCtor() throws IOException{ + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.enterprise.inject.Disposes; "+ + " public class Clazz { "+ + " public Clazz( int i){} "+ + " public Clazz( @Disposes String str ){} "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; "+ + " public class Clazz1 { "+ + " public Clazz1( int i){} "+ + " public Clazz1( @Observes String str ){} "+ + "}"); + + /* + * Create a good one class file + */ + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " public class Clazz2 { "+ + " public Clazz2( Stirng str ){} "+ + "}"); + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkCtor(result, "foo.Clazz"); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkCtor(result, "foo.Clazz1"); + } + + }; + runAnalysis(errorFile1 , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * ScopeAnalyzer + */ + public void testScope() throws IOException{ + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Scope1.java", + "package foo; " + + " import jakarta.inject.Scope; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.ANNOTATION_TYPE}) "+ + " @Scope "+ + " public @interface Scope1 { "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Scope2.java", + "package foo; " + + " import jakarta.inject.Scope; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Target({ElementType.METHOD,ElementType.FIELD, ElementType.TYPE}) "+ + " @Scope "+ + " public @interface Scope2 { "+ + "}"); + + /* + * Create a good one class file + */ + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Scope3.java", + "package foo; " + + " import jakarta.inject.Scope; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, ElementType.TYPE}) "+ + " @Scope "+ + " public @interface Scope3 { "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Scope1"); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Scope2"); + } + + }; + runAnalysis(errorFile1 , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * QualifierAnalyzer + */ + public void testQualifier() throws IOException{ + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Qualifier1.java", + "package foo; " + + " import jakarta.inject.Qualifier; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.ANNOTATION_TYPE}) "+ + " @Qualifier "+ + " public @interface Qualifier1 { "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Qualifier2.java", + "package foo; " + + " import jakarta.inject.Qualifier; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, ElementType.TYPE}) "+ + " @Qualifier "+ + " public @interface Qualifier2 { "+ + "}"); + + FileObject errorFile2 = TestUtilities.copyStringToFileObject(srcFO, "foo/Qualifier3.java", + "package foo; " + + " import jakarta.inject.Qualifier; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Target({ElementType.FIELD, ElementType.PARAMETER}) "+ + " @Qualifier "+ + " public @interface Qualifier3 { "+ + "}"); + + /* + * Create a good class files + */ + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Qualifier4.java", + "package foo; " + + " import jakarta.inject.Qualifier; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, " + + "ElementType.PARAMETER, ElementType.TYPE}) "+ + " @Qualifier "+ + " public @interface Qualifier4 { "+ + "}"); + + FileObject goodFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Qualifier5.java", + "package foo; " + + " import jakarta.inject.Qualifier; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.FIELD, ElementType.PARAMETER}) "+ + " @Qualifier "+ + " public @interface Qualifier5 { "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Qualifier1"); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Qualifier2"); + } + + }; + runAnalysis(errorFile1 , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Qualifier3"); + } + + }; + runAnalysis(errorFile2 , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + runAnalysis( goodFile1, NO_ERRORS_PROCESSOR ); + } + + /* + * QualifierAnalyzer checkMembers() + */ + public void testQualifierMembers() throws IOException{ + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Qualifier1.java", + "package foo; " + + " import jakarta.inject.Qualifier; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, " + + "ElementType.PARAMETER, ElementType.TYPE}) "+ + " @Qualifier "+ + " public @interface Qualifier1 { "+ + " String value(); "+ + " String[] comments(); "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Qualifier2.java", + "package foo; " + + " import jakarta.inject.Qualifier; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, " + + "ElementType.PARAMETER, ElementType.TYPE}) "+ + " @Qualifier "+ + " public @interface Qualifier2 { "+ + " String value(); "+ + " Qualifier1 qualifier(); "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Qualifier3.java", + "package foo; " + + " import jakarta.inject.Qualifier; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " import jakarta.enterprise.util.Nonbinding; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, " + + "ElementType.PARAMETER, ElementType.TYPE}) "+ + " @Qualifier "+ + " public @interface Qualifier3 { "+ + " String value(); "+ + " @Nonbinding "+ + " Qualifier1 qualifier(); "+ + " @Nonbinding "+ + " String[] comments(); "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result.getWarings(), "foo.Qualifier1"); + assertEquals( 0 , result.getErrors().size()); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result.getWarings(), "foo.Qualifier2"); + assertEquals( 0 , result.getErrors().size()); + } + + }; + runAnalysis(errorFile1 , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR); + } + + /* + * InterceptorBindingMembersAnalyzer checkMembers() + */ + public void testIBindingMembers() throws IOException{ + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/IBinding1.java", + "package foo; " + + " import jakarta.inject.Qualifier; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " import jakarta.interceptor.*; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, " + + "ElementType.PARAMETER, ElementType.TYPE}) "+ + "@InterceptorBinding " + + " public @interface IBinding1 { "+ + " String value(); "+ + " String[] comments(); "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/IBinding2.java", + "package foo; " + + " import jakarta.inject.Qualifier; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " import jakarta.interceptor.*; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, " + + "ElementType.PARAMETER, ElementType.TYPE}) "+ + "@InterceptorBinding " + + " public @interface IBinding2 { "+ + " String value(); "+ + " IBinding1 qualifier(); "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/IBinding3.java", + "package foo; " + + " import jakarta.inject.Qualifier; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " import jakarta.enterprise.util.Nonbinding; "+ + " import jakarta.interceptor.*; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, " + + "ElementType.PARAMETER, ElementType.TYPE}) "+ + "@InterceptorBinding " + + " public @interface IBinding3 { "+ + " String value(); "+ + " @Nonbinding "+ + " Qualifier1 qualifier(); "+ + " @Nonbinding "+ + " String[] comments(); "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result.getWarings(), "foo.IBinding1"); + assertEquals( 0 , result.getErrors().size()); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result.getWarings(), "foo.IBinding2"); + assertEquals( 0 , result.getErrors().size()); + } + + }; + runAnalysis(errorFile1 , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR); + } + +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiAnalysisTestResult.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiAnalysisTestResult.java new file mode 100644 index 000000000000..bc0ff205f82e --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiAnalysisTestResult.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.lang.model.element.Element; + +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.spi.editor.hints.ErrorDescription; +import org.netbeans.spi.editor.hints.Severity; + + +/** + * @author ads + * + */ +public class CdiAnalysisTestResult extends CdiAnalysisResult + implements TestProblems +{ + + public CdiAnalysisTestResult( CompilationInfo info ) { + super(info, null); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult#addError(javax.lang.model.element.Element, java.lang.String) + */ + @Override + public void addError( Element subject, String message ) { + /* TODO: method signature needs to be changed to get a key + * (id of message ) of bundle instead of localized message + */ + myErrors.put( subject , message ); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult#addNotification(org.netbeans.spi.editor.hints.Severity, javax.lang.model.element.Element, java.lang.String) + */ + @Override + public void addNotification( Severity severity, Element element, + String message ) + { + if ( severity == Severity.WARNING ){ + myWarnings.put( element , message ); + } + else { + assert false; + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult#getProblems() + */ + @Override + public List getProblems() { + return null; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult#requireCdiEnabled(javax.lang.model.element.Element) + */ + @Override + public void requireCdiEnabled( Element element ) { + } + + @Override + public Map getErrors(){ + return myErrors; + } + + @Override + public Map getWarings(){ + return myWarnings; + } + + private Map myErrors = new HashMap(); + private Map myWarnings = new HashMap(); +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiAnalysisTestTask.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiAnalysisTestTask.java new file mode 100644 index 000000000000..f7d790556eb0 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/CdiAnalysisTestTask.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import org.netbeans.api.java.source.CompilationInfo; + + +/** + * @author ads + * + */ +public class CdiAnalysisTestTask extends CdiAnalysisTask { + + + public CdiAnalysisTestTask( ) { + super(null); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisTask#run(org.netbeans.api.java.source.CompilationInfo) + */ + @Override + protected void run( CompilationInfo compInfo ) { + super.run(compInfo); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisTask#getResult() + */ + @Override + protected CdiAnalysisTestResult getResult() { + return (CdiAnalysisTestResult)super.getResult(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisTask#createResult(org.netbeans.api.java.source.CompilationInfo) + */ + @Override + protected CdiAnalysisResult createResult( CompilationInfo info ) { + return new CdiAnalysisTestResult(info); + } + +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/TestProblems.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/TestProblems.java new file mode 100644 index 000000000000..3a6c06315321 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/TestProblems.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import java.util.Map; + +import javax.lang.model.element.Element; + + +/** + * @author ads + * + */ +public interface TestProblems { + + Map getErrors(); + + Map getWarings(); +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/WebBeansAnalysisTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/WebBeansAnalysisTest.java new file mode 100644 index 000000000000..5a1322fdb746 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/WebBeansAnalysisTest.java @@ -0,0 +1,2148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import java.io.IOException; + +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +public class WebBeansAnalysisTest extends BaseAnalisysTestCase { + + + public WebBeansAnalysisTest(String testName) { + super(testName); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.BaseAnalisysTestCase#createTask() + */ + @Override + protected WebBeansAnalysisTestTask createTask() { + return new WebBeansAnalysisTestTask( getUtilities() ); + } + + //======================================================================= + // + // ClassModelAnalyzer - ManagedBeansAnalizer + // + //======================================================================= + /* + * ManagedBeansAnalizer.checkCtor + */ + public void testManagedBeansCtor() throws IOException { + getUtilities().createQualifier("Qualifier1"); + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + " @Qualifier1 "+ + " public class Clazz { "+ + " private Clazz(){} "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + " @Qualifier1 "+ + " public class Clazz1 { "+ + " public Clazz1( int i ){} "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + " @Qualifier1 "+ + " public class Clazz2 { "+ + "}"); + + FileObject goodFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz3.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " @Qualifier1 "+ + " public class Clazz3 { "+ + " @Inject public Clazz3( String str ){} "+ + "}"); + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result.getWarings(), "foo.Clazz"); + assertEquals( "Found unexpected errors", 0, result.getErrors().size()); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result.getWarings(), "foo.Clazz1"); + assertEquals( "Found unexpected errors", 0, result.getErrors().size()); + } + + }; + runAnalysis(errorFile1 , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + runAnalysis( goodFile1, NO_ERRORS_PROCESSOR ); + } + + /* + * ManagedBeansAnalizer.checkInner + */ + public void testManagedBeansInner() throws IOException { + getUtilities().createQualifier("Qualifier1"); + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + " public class Clazz { "+ + " @Qualifier1 "+ + " class Inner{} "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + " public class Clazz1 { "+ + " @Qualifier1 "+ + " static class Inner{} "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement( result , "foo.Clazz.Inner"); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * ManagedBeansAnalizer.checkAbstract + */ + public void testManagedBeansAbstract() throws IOException { + getUtilities().createQualifier("Qualifier1"); + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + " @Qualifier1 "+ + " public abstract class Clazz { "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.decorator.Decorator; "+ + "import jakarta.decorator.Delegate; "+ + "import jakarta.inject.Inject; "+ + " @Qualifier1 "+ + " @Decorator "+ + " public abstract class Clazz1 { "+ + " @Inject public Clazz1( @Qualifier1 @Delegate Clazz arg ){ "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement( result.getWarings() , "foo.Clazz"); + assertEquals( "Unxepected error found", 0, result.getErrors().size()); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * ManagedBeansAnalizer.checkImplementsExtension + */ + public void testManagedBeansImplementsExtension() throws IOException { + getUtilities().createQualifier("Qualifier1"); + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.enterprise.inject.spi.Extension "+ + " @Qualifier1 "+ + " public class Clazz implements Extension { "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + " @Qualifier1 "+ + " public class Clazz1 { "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement( result.getWarings() , "foo.Clazz"); + assertEquals( "Unxepected error found", 0, result.getErrors().size()); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + //======================================================================= + // + // ClassModelAnalyzer - ScopedBeanAnalyzer + // + //======================================================================= + + /* + * ScopedBeanAnalyzer.checkProxiability + */ + public void testScopedProxiability() throws IOException { + TestUtilities.copyStringToFileObject(srcFO, "foo/Scope1.java", + "package foo; " + + " import jakarta.inject.Scope; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, ElementType.TYPE}) "+ + " @Scope "+ + " public @interface Scope1 { "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Scope2.java", + "package foo; " + + " import jakarta.enterprise.context.NormalScope; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, ElementType.TYPE}) "+ + " @NormalScope "+ + " public @interface Scope2 { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + " @Scope2 "+ + " public final class Clazz { "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + " @Scope2 "+ + " public class Clazz1 { "+ + " public final void op(){} "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + " @Scope1 "+ + " public final class Clazz2 { "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement( result , "foo.Clazz"); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkMethodElement(result.getWarings() , "foo.Clazz1", "op"); + assertEquals( "Unxepected error found", 0, result.getErrors().size()); + } + + }; + runAnalysis(errorFile1 , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * ScopedBeanAnalyzer.checkPublicField + */ + public void testScopedPublicField() throws IOException { + TestUtilities.copyStringToFileObject(srcFO, "foo/Scope1.java", + "package foo; " + + " import jakarta.inject.Scope; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, ElementType.TYPE}) "+ + " @Scope "+ + " public @interface Scope1 { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + " @Scope1 "+ + " public class Clazz { "+ + " public int field; "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + " public class Clazz1 { "+ + " public int field; "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Clazz"); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * ScopedBeanAnalyzer.checkParameterizedBean + */ + public void testScopedParameterizedBean() throws IOException { + TestUtilities.copyStringToFileObject(srcFO, "foo/Scope1.java", + "package foo; " + + " import jakarta.inject.Scope; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, ElementType.TYPE}) "+ + " @Scope "+ + " public @interface Scope1 { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + " @Scope1 "+ + " public class Clazz { "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + " public class Clazz1 { "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Clazz"); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + /* + * ScopedBeanAnalyzer.checkInterceptorDecorator + */ + public void testScopedDecoratorInterceptor() throws IOException { + TestUtilities.copyStringToFileObject(srcFO, "foo/Scope1.java", + "package foo; " + + " import jakarta.inject.Scope; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, ElementType.TYPE}) "+ + " @Scope "+ + " public @interface Scope1 { "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface.java", + "package foo; " + + " public interface Iface { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.interceptor.Interceptor; "+ + " @Scope1 "+ + "@Interceptor "+ + " public class Clazz1 { "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + "import jakarta.decorator.Decorator; "+ + "import jakarta.decorator.Delegate; "+ + "import jakarta.inject.Inject; "+ + " @Scope1 "+ + "@Decorator "+ + " public class Clazz2 implements Iface{ "+ + " @Delegate @Inject Iface delegate; "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result.getWarings(), "foo.Clazz1"); + assertEquals( 0, result.getErrors().size() ); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result.getWarings(), "foo.Clazz2"); + assertEquals( 0, result.getErrors().size() ); + } + + }; + runAnalysis(errorFile1 , processor); + + } + + /* + * ScopedBeanAnalyzer.checkPassivationCapable + */ + public void testPassivation() throws IOException { + getUtilities().initEnterprise(); + TestUtilities.copyStringToFileObject(srcFO, "foo/Scope1.java", + "package foo; " + + " import jakarta.enterprise.context.NormalScope; " + + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, ElementType.TYPE}) "+ + " @NormalScope(passivating=true) "+ + " public @interface Scope1 { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.interceptor.Interceptor; "+ + " @Scope1 "+ + " public class Clazz1 { "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + " import jakarta.enterprise.context.SessionScoped; "+ + " @SessionScoped "+ + " public class Clazz2 { "+ + "}"); + + FileObject errorFile2 = TestUtilities.copyStringToFileObject(srcFO, "foo/SessionClazz.java", + "package foo; " + + " import jakarta.enterprise.context.SessionScoped; "+ + " import jakarta.ejb.Singleton; "+ + " @SessionScoped "+ + " @Singleton "+ + " public class SessionClazz { "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz3.java", + "package foo; " + + " import jakarta.enterprise.context.SessionScoped; "+ + " import java.io.Serializable; "+ + " @SessionScoped "+ + " public class Clazz3 implements Serializable { "+ + "}"); + + FileObject goodFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz4.java", + "package foo; " + + " import jakarta.enterprise.context.RequestScoped; "+ + " @RequestScoped "+ + " public class Clazz4{ "+ + "}"); + + FileObject goodFile2 = TestUtilities.copyStringToFileObject(srcFO, "foo/StatefulClazz.java", + "package foo; " + + " import jakarta.enterprise.context.SessionScoped; "+ + " import java.io.Serializable; "+ + " import jakarta.ejb.Stateful; "+ + " @SessionScoped "+ + " @Stateful "+ + " public class StatefulClazz { "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement( result, "foo.Clazz1"); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result,"foo.Clazz2"); + } + + }; + runAnalysis(errorFile1 , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result,"foo.SessionClazz"); + } + + }; + runAnalysis(errorFile2 , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR); + runAnalysis( goodFile1, NO_ERRORS_PROCESSOR); + runAnalysis( goodFile2, NO_ERRORS_PROCESSOR); + } + + //======================================================================= + // + // ClassModelAnalyzer - SessionBeanAnalyzer + // + //======================================================================= + + public void testSessionBean() throws IOException { + getUtilities().initEnterprise(); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Scope1.java", + "package foo; " + + " import jakarta.inject.Scope; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, ElementType.TYPE}) "+ + " @Scope "+ + " public @interface Scope1 { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.ejb.Singleton; "+ + " @Scope1 "+ + " @Singleton "+ + " public class Clazz { "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.ejb.Stateless; "+ + " @Scope1 "+ + " @Stateless "+ + " public class Clazz1 { "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + "import jakarta.enterprise.context.ApplicationScoped; "+ + "import jakarta.ejb.Singleton; "+ + " @Singleton "+ + " @ApplicationScoped "+ + " public class Clazz2 { "+ + "}"); + + FileObject goodFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz3.java", + "package foo; " + + "import jakarta.ejb.Stateless; "+ + " @Stateless "+ + " public class Clazz3 { "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Clazz"); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Clazz1"); + } + + }; + runAnalysis(errorFile1 , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + runAnalysis( goodFile1, NO_ERRORS_PROCESSOR ); + } + + //======================================================================= + // + // ClassModelAnalyzer - InterceptedBeanAnalyzer + // + //======================================================================= + + public void testInterceptedBean() throws IOException { + getUtilities().createInterceptorBinding("IBinding"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + " @IBinding "+ + " public class Clazz { "+ + " public final void method(){} "+ + " private final void privateMethod(){} "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + " @IBinding "+ + " public final class Clazz1 { "+ + " static void staticMethod(){} "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + " @IBinding "+ + " public class Clazz2 { "+ + " private final void privateMethod(){} "+ + " final static void staticMethod(){} "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Clazz"); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Clazz1"); + } + + }; + runAnalysis(errorFile1 , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + //======================================================================= + // + // ClassModelAnalyzer - NamedModelAnalyzer + // + //======================================================================= + + public void testNamed() throws IOException { + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/SuperClass.java", + "package foo; " + + " import jakarta.inject.Named; "+ + "@Named "+ + " public class SuperClass { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + " import jakarta.inject.Named; "+ + " import jakarta.enterprise.inject.Specializes; "+ + "@Named "+ + "@Specializes "+ + " public class Clazz extends SuperClass { "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperClass1.java", + "package foo; " + + " public class SuperClass1 { "+ + "}"); + + FileObject goodFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + " import jakarta.inject.Named; "+ + " import jakarta.enterprise.inject.Specializes; "+ + "@Named "+ + "@Specializes "+ + " public class Clazz1 extends SuperClass1 { "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Clazz"); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + runAnalysis( goodFile1, NO_ERRORS_PROCESSOR ); + } + + //======================================================================= + // + // ClassModelAnalyzer - DeclaredIBindingsAnalyzer + // + //======================================================================= + + public void testIBindingsDuplication() throws IOException { + + TestUtilities.copyStringToFileObject(srcFO, "foo/IBinding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.interceptor.*; "+ + "@InterceptorBinding " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, TYPE}) "+ + "public @interface IBinding1 {" + + " String value(); "+ + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/IBinding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.interceptor.*; "+ + "@InterceptorBinding " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, TYPE}) "+ + "@IBinding1(\"a\") "+ + "public @interface IBinding2 {} "); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + " @IBinding1(\"b\") @IBinding2 " + + " public class Clazz { "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + " @IBinding1(\"a\") @IBinding2 " + + " public class Clazz1 { "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Clazz"); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + } + + //======================================================================= + // + // FieldModelAnalyzer - ScopedFieldAnalyzer + // + //======================================================================= + public void testScopedProducerField() throws IOException { + TestUtilities.copyStringToFileObject(srcFO, "foo/Scope1.java", + "package foo; " + + " import jakarta.inject.Scope; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, ElementType.TYPE}) "+ + " @Scope "+ + " public @interface Scope1 { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.enterprise.inject.Produces; "+ + " public class Clazz { "+ + " @Produces @Scope1 T producerField; "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.enterprise.inject.Produces; "+ + " public class Clazz1 { "+ + " @Produces T producerField; "+ + "}"); + + FileObject goodFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + " public class Clazz2 { "+ + " private T field; "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result, "foo.Clazz", "producerField"); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + runAnalysis( goodFile1, NO_ERRORS_PROCESSOR ); + } + + /* + * ScopedFieldAnalyzer.checkPassivationCapable + */ + public void testPassivationProductionField() throws IOException { + TestUtilities.copyStringToFileObject(srcFO, "foo/FinalClass.java", + "package foo; " + + " public final class FinalClass { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + " import jakarta.enterprise.context.SessionScoped; "+ + " import jakarta.enterprise.inject.Produces; "+ + " public class Clazz1 { "+ + " @Produces @SessionScoped FinalClass field; "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + " import jakarta.enterprise.context.SessionScoped; "+ + " import jakarta.enterprise.inject.Produces; "+ + " public class Clazz2 { "+ + " @Produces @SessionScoped int field; "+ + "}"); + + FileObject goodFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz3.java", + "package foo; " + + " import jakarta.enterprise.context.RequestScoped; "+ + " import jakarta.enterprise.inject.Produces; "+ + " public class Clazz3 { "+ + " @Produces @RequestScoped FinalClass field; "+ + "}"); + + FileObject goodFile2 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz4.java", + "package foo; " + + " import java.io.Serializable; "+ + " import jakarta.enterprise.context.SessionScoped; "+ + " import jakarta.enterprise.inject.Produces; "+ + " public class Clazz4 { "+ + " @Produces @SessionScoped Serializable field; "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result, "foo.Clazz1", "field"); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR); + runAnalysis( goodFile1, NO_ERRORS_PROCESSOR); + runAnalysis( goodFile2, NO_ERRORS_PROCESSOR); + } + + //======================================================================= + // + // FieldModelAnalyzer - InjectionPointAnalyzer + // + //======================================================================= + + /* + * InjectionPointAnalyzer.checkInjectionPointMetadata + */ + public void testInjectionPointMetadata() throws IOException { + getUtilities().createQualifier("Qualifier1"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Scope1.java", + "package foo; " + + " import jakarta.inject.Scope; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, ElementType.TYPE}) "+ + " @Scope "+ + " public @interface Scope1 { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.enterprise.inject.spi.InjectionPoint; "+ + "import jakarta.inject.Inject; "+ + " @Scope1 "+ + " public class Clazz { "+ + " @Inject InjectionPoint injectionMeta; "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.enterprise.inject.spi.InjectionPoint; "+ + "import jakarta.inject.Inject; "+ + " public class Clazz1 { "+ + " @Inject InjectionPoint injectionMeta; "+ + "}"); + + FileObject goodFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + "import jakarta.enterprise.inject.spi.InjectionPoint; "+ + "import jakarta.inject.Inject; "+ + " @Scope1 "+ + " public class Clazz2 { "+ + " @Inject @Qualifier1 InjectionPoint injectionMeta; "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result, "foo.Clazz", "injectionMeta"); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, WARNINGS_PROCESSOR ); + runAnalysis( goodFile1, WARNINGS_PROCESSOR ); + } + + /* + * InjectionPointAnalyzer.checkNamed + */ + public void testNamedInjectionPoint() throws IOException { + + TestUtilities.copyStringToFileObject(srcFO, "foo/BeanType.java", + "package foo; " + + " @Scope1 "+ + " public class BeanType { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " import jakarta.inject.Named; "+ + " public class Clazz { "+ + " @Inject @Named BeanType injectionPoint; "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result.getWarings(), "foo.Clazz", "injectionPoint"); + assertEquals( 0, result.getErrors().size()); + } + + }; + runAnalysis(errorFile , processor); + + } + + /* + * InjectionPointAnalyzer.checkResult : typesafe resolution checks + */ + public void testInjectableResult() throws IOException { + getUtilities().createQualifier("Qualifier1"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface.java", + "package foo; " + + " public interface Iface { "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/ImplClass.java", + "package foo; " + + " public class ImplClass implements Iface { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " public class Clazz { "+ + " @Inject @Qualifier1 Iface injectioPoint; "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " public class Clazz1 { "+ + " @Inject Iface injectioPoint; "+ + "}"); + + FileObject goodFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + "import jakarta.enterprise.context.spi.Context; "+ + " public class Clazz2 { "+ + " @Inject Context injectioPoint; "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result.getWarings(), "foo.Clazz", "injectioPoint"); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + runAnalysis( goodFile1, NO_ERRORS_PROCESSOR ); + } + + /* + * InjectionPointAnalyzer.checkResult : defenition errors ( DefinitionErrorResult impl ) + */ + public void testDefinitionErrorResult() throws IOException { + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " public class Clazz { "+ + " @Inject int injectioPoint=0; "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " public class Clazz1 { "+ + " static @Inject int injectioPoint; "+ + "}"); + + FileObject errorFile2 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " public class Clazz2 { "+ + " final @Inject int injectioPoint; "+ + "}"); + + FileObject errorFile3 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz3.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + "import jakarta.enterprise.inject.Produces; "+ + " public class Clazz3 { "+ + " @Produces @Inject int injectioPoint; "+ + "}"); + + FileObject errorFile4 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz4.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + "import jakarta.enterprise.inject.Produces; "+ + " public class Clazz4 { "+ + " @Inject T injectioPoint; "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result, "foo.Clazz", "injectioPoint"); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result, "foo.Clazz1", "injectioPoint"); + } + + }; + runAnalysis(errorFile1 , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result, "foo.Clazz2", "injectioPoint"); + } + + }; + runAnalysis(errorFile2 , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result, "foo.Clazz3", "injectioPoint"); + } + + }; + runAnalysis(errorFile3 , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result, "foo.Clazz4", "injectioPoint"); + } + + }; + runAnalysis(errorFile4 , processor); + } + + /* + * InjectionPointAnalyzer.analyzeDecoratedBeans + */ + public void testDecoratedBean() throws IOException { + getUtilities().createQualifier("Qualifier1"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface1.java", + "package foo; " + + " public interface Iface1 { "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/DecoratedBean1.java", + "package foo; " + + " @Qualifier1 "+ + " public final class DecoratedBean1 implements Iface1 { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + "import jakarta.decorator.Delegate; "+ + "import jakarta.decorator.Decorator; "+ + " @Decorator "+ + " public class Clazz implements Iface1 { "+ + " @Qualifier1 @Inject @Delegate Iface1 delegate; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface2.java", + "package foo; " + + " public interface Iface2 { "+ + " void method();"+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/DecoratedBean2.java", + "package foo; " + + " @Qualifier1 "+ + " public class DecoratedBean2 implements Iface2 { "+ + " public final void method() { } "+ + " private final void op() { } "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + "import jakarta.decorator.Delegate; "+ + "import jakarta.decorator.Decorator; "+ + " @Decorator "+ + " public class Clazz1 implements Iface2 { "+ + " @Qualifier1 @Inject @Delegate Iface2 delegate; "+ + " public void method() { } "+ + " private final void op() { } "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface3.java", + "package foo; " + + " public interface Iface3 { "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/DecoratedBean3.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " @Qualifier1 "+ + " public class DecoratedBean3 implements Iface3 { "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + "import jakarta.decorator.Delegate; "+ + "import jakarta.decorator.Decorator; "+ + " @Decorator "+ + " public class Clazz2 implements Iface3 { "+ + " @Qualifier1 @Inject @Delegate Iface3 delegate; "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result, "foo.Clazz", "delegate"); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkFieldElement(result, "foo.Clazz1", "delegate"); + } + + }; + runAnalysis(errorFile1 , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + + } + + //======================================================================= + // + // MethodModelAnalyzer - ScopedMethodAnalyzer + // + //======================================================================= + public void testScopedProducerMethod() throws IOException { + TestUtilities.copyStringToFileObject(srcFO, "foo/Scope1.java", + "package foo; " + + " import jakarta.inject.Scope; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, ElementType.TYPE}) "+ + " @Scope "+ + " public @interface Scope1 { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.enterprise.inject.Produces; "+ + " public class Clazz { "+ + " @Produces @Scope1 T producerMethod(){ return null; } "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.enterprise.inject.Produces; "+ + " public class Clazz1 { "+ + " @Produces T producerMethod(){ return null; } "+ + "}"); + + FileObject goodFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + " public class Clazz2 { "+ + " private T method(){ return null; } "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz", "producerMethod"); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + runAnalysis( goodFile1, NO_ERRORS_PROCESSOR ); + } + + /* + * ScopedMethodAnalyzer.checkPassivationCapable + */ + public void testPassivationProductionMethod() throws IOException { + TestUtilities.copyStringToFileObject(srcFO, "foo/FinalClass.java", + "package foo; " + + " public final class FinalClass { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + " import jakarta.enterprise.context.SessionScoped; "+ + " import jakarta.enterprise.inject.Produces; "+ + " public class Clazz1 { "+ + " @Produces @SessionScoped FinalClass method(){ return null; } "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + " import jakarta.enterprise.context.SessionScoped; "+ + " import jakarta.enterprise.inject.Produces; "+ + " public class Clazz2 { "+ + " @Produces @SessionScoped int method(){ return 0; } "+ + "}"); + + FileObject goodFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz3.java", + "package foo; " + + " import jakarta.enterprise.context.RequestScoped; "+ + " import jakarta.enterprise.inject.Produces; "+ + " public class Clazz3 { "+ + " @Produces @RequestScoped FinalClass method(){ return null; } "+ + "}"); + + FileObject goodFile2 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz4.java", + "package foo; " + + " import java.io.Serializable; "+ + " import jakarta.enterprise.context.SessionScoped; "+ + " import jakarta.enterprise.inject.Produces; "+ + " public class Clazz4 { "+ + " @Produces @SessionScoped Serializable method(){ return null; } "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz1", "method"); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR); + runAnalysis( goodFile1, NO_ERRORS_PROCESSOR); + runAnalysis( goodFile2, NO_ERRORS_PROCESSOR); + } + + //======================================================================= + // + // MethodModelAnalyzer - InjectionPointParameterAnalyzer + // + //======================================================================= + + /* + * InjectionPointParameterAnalyzer.checkResult : typesafe resolution checks + */ + public void testInjectableParamResult() throws IOException { + getUtilities().createQualifier("Qualifier1"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface.java", + "package foo; " + + " public interface Iface { "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/ImplClass.java", + "package foo; " + + " public class ImplClass implements Iface { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " public class Clazz { "+ + " @Inject void method(@Qualifier1 Iface injectionPoint ){} "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " public class Clazz1 { "+ + " @Inject void method(Iface injectioPoint){} "+ + "}"); + + FileObject goodFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + "import jakarta.enterprise.context.spi.Context; "+ + " public class Clazz2 { "+ + " @Inject void method( Context injectioPoint) {} "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkParamElement( result.getWarings(), "foo.Clazz", "method", + "injectionPoint"); + assertEquals( "Found unexpected errors", 0, result.getErrors().size()); + } + + }; + runAnalysis(errorFile , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + runAnalysis( goodFile1, NO_ERRORS_PROCESSOR ); + } + + /* + * InjectionPointParameterAnalyzer.checkResult : defenition errors ( DefinitionErrorResult impl ) + */ + public void testParamDefinitionErrorResult() throws IOException { + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + "import jakarta.enterprise.inject.Produces; "+ + " public class Clazz1 { "+ + " @Inject void method( T injectioPoint ){} "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkParamElement(result, "foo.Clazz1", "method", "injectioPoint"); + } + + }; + runAnalysis(errorFile , processor); + + } + + /* + * InjectionPointParameterAnalyzer.checkName + */ + public void testNamedParameter() throws IOException { + + TestUtilities.copyStringToFileObject(srcFO, "foo/BeanType.java", + "package foo; " + + " public class BeanType { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " import jakarta.inject.Named; "+ + " public class Clazz1 { "+ + " @Inject void method( @Named BeanType injectionPoint ){} "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " import jakarta.inject.Named; "+ + " public class Clazz2 { "+ + " @Inject void method( @Named(\"paramName\") BeanType injectionPoint ){} "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkParamElement(result, "foo.Clazz1", "method", "injectionPoint"); + checkParamElement(result.getWarings(), "foo.Clazz1", "method", + "injectionPoint"); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkParamElement(result.getWarings(), "foo.Clazz2", "method", + "injectionPoint"); + assertEquals( 0, result.getErrors().size()); + } + + }; + runAnalysis(errorFile1 , processor); + + } + + /* + * InjectionPointAnalyzer.analyzeDecoratedBeans + */ + public void testParamDecoratedBean() throws IOException { + getUtilities().createQualifier("Qualifier1"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface1.java", + "package foo; " + + " public interface Iface1 { "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/DecoratedBean1.java", + "package foo; " + + " @Qualifier1 "+ + " public final class DecoratedBean1 implements Iface1 { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + "import jakarta.decorator.Delegate; "+ + "import jakarta.decorator.Decorator; "+ + " @Decorator "+ + " public class Clazz implements Iface1 { "+ + " @Inject void init( @Qualifier1 @Delegate Iface1 delegate){} "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface2.java", + "package foo; " + + " public interface Iface2 { "+ + " void method();"+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/DecoratedBean2.java", + "package foo; " + + " @Qualifier1 "+ + " public class DecoratedBean2 implements Iface2 { "+ + " public final void method() { } "+ + " private final void op() { } "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + "import jakarta.decorator.Delegate; "+ + "import jakarta.decorator.Decorator; "+ + " @Decorator "+ + " public class Clazz1 implements Iface2 { "+ + " @Inject void init ( @Qualifier1 @Delegate Iface2 delegate) {} "+ + " public void method() { } "+ + " private final void op() { } "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface3.java", + "package foo; " + + " public interface Iface3 { "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/DecoratedBean3.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + " @Qualifier1 "+ + " public class DecoratedBean3 implements Iface3 { "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + "import jakarta.inject.Inject; "+ + "import jakarta.decorator.Delegate; "+ + "import jakarta.decorator.Decorator; "+ + " @Decorator "+ + " public class Clazz2 implements Iface3 { "+ + " @Inject void init( @Qualifier1 @Delegate Iface3 delegate){} "+ + "}"); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkParamElement(result, "foo.Clazz", "init", "delegate"); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkParamElement(result, "foo.Clazz1", "init", "delegate"); + } + + }; + runAnalysis(errorFile1 , processor); + + runAnalysis( goodFile, NO_ERRORS_PROCESSOR ); + + } + + //======================================================================= + // + // MethodModelAnalyzer - InterceptedMethodAnalyzer + // + //======================================================================= + public void testInterceptedMethod() throws IOException { + getUtilities().initEnterprise(); + getUtilities().createInterceptorBinding("IBinding1"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/IBinding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.interceptor.*; "+ + "@InterceptorBinding " + + "@Retention(RUNTIME) "+ + "@Target({TYPE}) "+ + "public @interface IBinding2 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/ICeptor.java", + "package foo; " + + " import jakarta.interceptor.Interceptor; "+ + " @Interceptor @IBinding1 "+ + " public class ICeptor { "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/ICeptor1.java", + "package foo; " + + " import jakarta.interceptor.Interceptor; "+ + " @Interceptor @IBinding2 "+ + " public class ICeptor1 { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.ejb.PostActivate; "+ + " public class Clazz { "+ + " @IBinding1 "+ + " @PostActivate "+ + " public void method(){} "+ + "}"); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + " public class Clazz1 { "+ + " @IBinding1 "+ + " public final void method(){} "+ + "}"); + + FileObject errorFile2 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + " public final class Clazz2 { "+ + " @IBinding1 "+ + " public void method(){} "+ + "}"); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz3.java", + "package foo; " + + "import jakarta.ejb.PrePassivate; "+ + " @IBinding2 "+ + " public class Clazz3 { "+ + " @PrePassivate "+ + " public void method(){} "+ + " @IBinding1 "+ + " private final void method1(){} "+ + "}"); + + FileObject goodFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz4.java", + "package foo; " + + " public final class Clazz4 { "+ + " public void method(){} "+ + "}"); + + FileObject goodFile2 = TestUtilities.copyStringToFileObject(srcFO, "foo/ICeptor2.java", + "package foo; " + + " import jakarta.interceptor.Interceptor; "+ + " @Interceptor @IBinding2 "+ + " public final class ICeptor2 { "+ + " public final void method(){} "+ + "}"); + + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkMethodElement(result.getWarings(), "foo.Clazz", "method"); + checkMethodElement(result, "foo.Clazz", "method"); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz1", "method"); + assertEquals( "Unexpected warings found", 0, result.getWarings().size()); + } + + }; + runAnalysis(errorFile1 , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkMethodElement(result, "foo.Clazz2", "method"); + assertEquals( "Unexpected warings found", 0, result.getWarings().size()); + } + + }; + runAnalysis(errorFile2 , processor); + + runAnalysis(goodFile, NO_ERRORS_PROCESSOR); + runAnalysis(goodFile1, NO_ERRORS_PROCESSOR); + runAnalysis(goodFile2, NO_ERRORS_PROCESSOR); + } + + //======================================================================= + // + // AnnotationModelAnalyzer - StereotypeAnalyzer + // + //======================================================================= + + /* + * StereotypeAnalyzer.analyzeScope + */ + public void testScopedStereotype() throws IOException { + + TestUtilities.copyStringToFileObject(srcFO, "foo/Scope1.java", + "package foo; " + + " import jakarta.inject.Scope; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, ElementType.TYPE}) "+ + " @Scope "+ + " public @interface Scope1 { "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Scope2.java", + "package foo; " + + " import jakarta.inject.Scope; "+ + " import java.lang.annotation.Retention; "+ + " import java.lang.annotation.RetentionPolicy; "+ + " import java.lang.annotation.Target; " + + " import java.lang.annotation.ElementType; "+ + " @Retention(RetentionPolicy.RUNTIME) "+ + " @Target({ElementType.METHOD,ElementType.FIELD, ElementType.TYPE}) "+ + " @Scope "+ + " public @interface Scope2 { "+ + "}"); + + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + " @Scope1 @Scope2 "+ + "public @interface Stereotype1 {}" ); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + " @Stereotype3 @Stereotype4 "+ + "public @interface Stereotype2 {}" ); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype3.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + " @Scope1 "+ + "public @interface Stereotype3 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype4.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + " @Scope2 "+ + "public @interface Stereotype4 {}" ); + + ResultProcessor processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Stereotype1"); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Stereotype2"); + } + + }; + runAnalysis(errorFile1 , processor); + + runAnalysis(goodFile, NO_ERRORS_PROCESSOR); + } + + /* + * StereotypeAnalyzer. checkName, checkDefinition, checkInterceptorBindings, checkTransitiveStereotypes + */ + public void testStereotype() throws IOException { + getUtilities().createInterceptorBinding("IBinding1"); + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.Named; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + " @Named(\"name\") " + + "public @interface Stereotype1 {}" ); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.SOURCE; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(SOURCE) "+ + "@Stereotype "+ + "public @interface Stereotype2 {}" ); + + FileObject errorFile2 = TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype3.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + "public @interface Stereotype3 {}" ); + + FileObject errorFile3 = TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype4.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + " @IBinding1 "+ + "public @interface Stereotype4 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TypeStereotype.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.Named; "+ + "@Target({TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + "public @interface TypeStereotype {}" ); + + FileObject errorFile4 = TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype5.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + " @TypeStereotype "+ + "public @interface Stereotype5 {}" ); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/GoodStereotype1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.Named; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + " @Named " + + "public @interface GoodStereotype1 {}" ); + + FileObject goodFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/GoodStereotype2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.Named; "+ + "@Target({TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + " @Named " + + " @IBinding1 "+ + "public @interface GoodStereotype2 {}" ); + + ResultProcessor processor = new ResultProcessor (){ + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Stereotype1"); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Stereotype2"); + } + + }; + runAnalysis(errorFile1 , processor); + + processor = new ResultProcessor (){ + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Stereotype3"); + } + + }; + runAnalysis(errorFile2 , processor); + + processor = new ResultProcessor (){ + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Stereotype4"); + } + + }; + runAnalysis(errorFile3 , processor); + + processor = new ResultProcessor (){ + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.Stereotype5"); + } + + }; + runAnalysis(errorFile4 , processor); + + runAnalysis(goodFile, NO_ERRORS_PROCESSOR); + runAnalysis(goodFile1, NO_ERRORS_PROCESSOR); + } + + /* + * StereotypeAnalyzer. checkQualifiers, checkTyped + */ + public void testQualifiedTypedStereotype() throws IOException { + getUtilities().createQualifier("Qualifier1"); + FileObject errorFile = TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + "@Qualifier1 "+ + "public @interface Stereotype1 {}" ); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.enterprise.inject.Typed; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + "@Typed({}) "+ + "public @interface Stereotype2 {}" ); + + ResultProcessor processor = new ResultProcessor (){ + @Override + public void process( TestProblems result ) { + checkTypeElement(result.getWarings(), "foo.Stereotype1"); + assertEquals( 0, result.getErrors().size()); + } + + }; + runAnalysis(errorFile , processor); + + processor = new ResultProcessor (){ + @Override + public void process( TestProblems result ) { + checkTypeElement(result.getWarings(), "foo.Stereotype2"); + assertEquals( 0, result.getErrors().size()); + } + + }; + runAnalysis(errorFile1 , processor); + + } + + //======================================================================= + // + // AnnotationModelAnalyzer - InterceptorBindingAnalyzer + // + //======================================================================= + + public void testInterceptorBinding() throws IOException { + + TestUtilities.copyStringToFileObject(srcFO, "foo/TypeBinding.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.interceptor.*; "+ + "@InterceptorBinding " + + "@Retention(RUNTIME) "+ + "@Target({TYPE}) "+ + "public @interface TypeBinding {} "); + + FileObject errorFile1 = TestUtilities.copyStringToFileObject(srcFO, "foo/IBinding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.SOURCE; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.interceptor.*; "+ + "@InterceptorBinding " + + "@Retention(SOURCE) "+ + "@Target({TYPE, METHOD}) "+ + "public @interface IBinding1 {} "); + + FileObject goodFile2 = TestUtilities.copyStringToFileObject(srcFO, "foo/IBinding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.interceptor.*; "+ + "@InterceptorBinding " + + "@Retention(RUNTIME) "+ + "@Target({METHOD}) "+ + "public @interface IBinding2 {} "); + + FileObject errorFile3 = TestUtilities.copyStringToFileObject(srcFO, "foo/IBinding3.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.interceptor.*; "+ + "@InterceptorBinding " + + "@Retention(RUNTIME) "+ + "@Target({TYPE, METHOD}) "+ + " @TypeBinding "+ + "public @interface IBinding3 {} "); + + FileObject goodFile = TestUtilities.copyStringToFileObject(srcFO, "foo/IBinding4.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.interceptor.*; "+ + "@InterceptorBinding " + + "@Retention(RUNTIME) "+ + "@Target({TYPE}) "+ + " @TypeBinding "+ + "public @interface IBinding4 {} "); + + ResultProcessor processor = new ResultProcessor (){ + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.IBinding1"); + } + + }; + runAnalysis(errorFile1 , processor); + + runAnalysis(goodFile2 , NO_ERRORS_PROCESSOR); + + processor = new ResultProcessor (){ + @Override + public void process( TestProblems result ) { + checkTypeElement(result, "foo.IBinding3"); + } + + }; + runAnalysis(errorFile3 , processor); + + runAnalysis(goodFile, NO_ERRORS_PROCESSOR); + } +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/WebBeansAnalysisTestResult.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/WebBeansAnalysisTestResult.java new file mode 100644 index 000000000000..88c34b027f7e --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/WebBeansAnalysisTestResult.java @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; + +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.modules.jakarta.web.beans.analysis.analyzer.ModelAnalyzer.Result; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.spi.editor.hints.ErrorDescription; +import org.netbeans.spi.editor.hints.Severity; + + +/** + * @author ads + * + */ +public class WebBeansAnalysisTestResult extends Result implements TestProblems { + + public WebBeansAnalysisTestResult( CompilationInfo info) + { + super(info, null); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult#addError(jakarta.lang.model.element.Element, java.lang.String) + */ + @Override + public void addError( Element subject, String message ) { + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult#addNotification(org.netbeans.spi.editor.hints.Severity, javax.lang.model.element.Element, java.lang.String) + */ + @Override + public void addNotification( Severity severity, Element element, + String message ) + { + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult#getProblems() + */ + @Override + public List getProblems() { + return null; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisResult#requireCdiEnabled(javax.lang.model.element.Element) + */ + @Override + public void requireCdiEnabled( Element element ) { + } + + public void addNotification( Severity severity, Element element, + WebBeansModel model, String message ) + { + ElementHandle handle = ElementHandle.create(element); + Element origElement = handle.resolve(getInfo()); + if ( severity == Severity.ERROR){ + myErrors.put( origElement , message ); + } + else if ( severity == Severity.WARNING){ + myWarnings.put( origElement , message ); + } + else { + assert false; + } + } + + public void addNotification( Severity severity, + VariableElement element, ExecutableElement method, + WebBeansModel model, String message ) + { + int index = method.getParameters().indexOf( element ); + ElementHandle handle = ElementHandle.create(method); + ExecutableElement origMethod = handle.resolve(getInfo()); + VariableElement param = origMethod.getParameters().get(index); + if ( severity == Severity.ERROR){ + myErrors.put( param , message ); + } + else if ( severity == Severity.WARNING){ + myWarnings.put( param , message ); + } + else { + assert false; + } + } + + public void requireCdiEnabled( Element element , WebBeansModel model){ + } + + public void requireCdiEnabled( VariableElement element , + ExecutableElement method ,WebBeansModel model) + { + } + + @Override + public Map getErrors(){ + return myErrors; + } + + @Override + public Map getWarings(){ + return myWarnings; + } + + private Map myErrors = new HashMap(); + private Map myWarnings = new HashMap(); + +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/WebBeansAnalysisTestTask.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/WebBeansAnalysisTestTask.java new file mode 100644 index 000000000000..2e5dbed1071f --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/analysis/WebBeansAnalysisTestTask.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.analysis; + +import org.netbeans.api.java.source.CompilationInfo; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.jakarta.web.beans.MetaModelSupport; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.testutilities.CdiTestUtilities; + + + +/** + * @author ads + * + */ +public class WebBeansAnalysisTestTask extends WebBeansAnalysisTask { + + public WebBeansAnalysisTestTask( CdiTestUtilities utilities ){ + super(null); + myUtilities = utilities; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisTask#run(org.netbeans.api.java.source.CompilationInfo) + */ + @Override + protected void run( CompilationInfo compInfo ) { + super.run(compInfo); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisTask#getResult() + */ + @Override + protected WebBeansAnalysisTestResult getResult() { + return (WebBeansAnalysisTestResult)super.getResult(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.CdiAnalysisTask#createResult(org.netbeans.api.java.source.CompilationInfo) + */ + @Override + protected WebBeansAnalysisTestResult createResult( CompilationInfo info ) { + return new WebBeansAnalysisTestResult(info); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.analysis.WebBeansAnalysisTask#getModel(CompilationInfo) + */ + protected MetadataModel getModel(CompilationInfo compInfo){ + try { + return myUtilities.createBeansModel(); + } + catch ( Exception e ){ + e.printStackTrace(); + assert false : e.getMessage(); + } + return null; + } + + private CdiTestUtilities myUtilities; +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/AlternativeTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/AlternativeTest.java new file mode 100644 index 000000000000..db68b876d483 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/AlternativeTest.java @@ -0,0 +1,1153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class AlternativeTest extends CommonTestCase { + + public AlternativeTest( String testName ) { + super(testName); + } + + public void testAlternativeDisabled() throws IOException{ + TestUtilities.copyStringToFileObject(srcFO, "beans.xml", + " " + + "" + + "" + + " " + + ""); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding2 {}"); + + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "@Binding1 "+ + "public class Two extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + "@Alternative "+ + "public class Three extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One1.java", + "package foo; " + + "public class One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two1.java", + "package foo; " + + "@Binding1 @Binding2 "+ + "public class Two1 extends One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Four.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + "@Stereotype1 "+ + "public class Four extends One1{}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Five.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding2 @Binding1 "+ + "@Stereotype2 "+ + "public class Five extends One1{}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Alternative "+ + "@Stereotype "+ + "public @interface Stereotype1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + "@Stereotype1 "+ + "public @interface Stereotype2 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class TestClass {" + + " @Inject @Binding1 One myField1; "+ + " @Inject @Binding1 One1 myField2; "+ + " @Inject @Binding1 @Binding2 One1 myField3; "+ + "}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myField1")){ + check1( element , model ); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + check2( element , model); + } + else if ( element.getSimpleName().contentEquals("myField3")){ + check3( element , model); + } + } + + assert names.contains("myField1"); + assert names.contains("myField2"); + assert names.contains("myField3"); + return null; + } + }); + } + + public void testAlternativeEnabled() throws IOException{ + TestUtilities.copyStringToFileObject(srcFO, "beans.xml", + " " + + "" + + "" + + "foo.Three "+ + "foo.Stereotype1 "+ + " " + + ""); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding2 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "@Binding1 "+ + "public class Two extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 @Binding2 "+ + "@Alternative "+ + "public class Three extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One1.java", + "package foo; " + + "@Binding2 "+ + "@Stereotype3 "+ + "public class One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Four.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding2 "+ + "@Stereotype1 "+ + "public class Four extends One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Five.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding2 @Binding1 "+ + "@Stereotype2 "+ + "public class Five extends One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class TestClass {" + + " @Inject @Binding1 @Binding2 One myField1; "+ + " @Inject @Binding2 One1 myField2; "+ + " @Inject @Binding2 @Binding1 One1 myField3; "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Alternative "+ + "@Stereotype "+ + "public @interface Stereotype1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + "@Stereotype1 "+ + "public @interface Stereotype2 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype3.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Alternative "+ + "@Stereotype "+ + "public @interface Stereotype3 {}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myField1")){ + checkEnabled1( element , model ); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + checkEnabled2( element , model); + } + else if ( element.getSimpleName().contentEquals("myField3")){ + checkEnabled3( element , model); + } + } + + assert names.contains("myField1"); + assert names.contains("myField2"); + assert names.contains("myField3"); + return null; + } + + }); + } + + public void testMixedAlternativeStereotype() throws IOException{ + TestUtilities.copyStringToFileObject(srcFO, "beans.xml", + " " + + "" + + "" + + "foo.Three "+ + "foo.Stereotype1 "+ + " " + + ""); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + " @Alternative "+ + " @Stereotype1 " + + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "@Binding1 "+ + " @Stereotype1 "+ + "public class Two extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + "@Alternative "+ + " @Stereotype1 "+ + "public class Three {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class TestClass {" + + " @Inject @Binding1 One myField1; "+ + " @Inject @Binding1 Three myField2; "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Alternative "+ + "@Stereotype "+ + "public @interface Stereotype1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + "@Alternative "+ + "public @interface Stereotype2 {}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myField1")){ + checkMixed1( element , model ); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + checkMixed2( element , model); + } + } + + assert names.contains("myField1"); + assert names.contains("myField2"); + return null; + } + + }); + } + + public void testProductionAlternatives() throws IOException{ + TestUtilities.copyStringToFileObject(srcFO, "beans.xml", + " " + + "" + + "" + + "foo.One "+ + "foo.Stereotype1 "+ + " " + + ""); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {}"); + + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + " @Alternative "+ + "public class One {" + + " @Alternative @Produces @Binding1 int myField1; "+ + " @Alternative @Stereotype2 @Produces @Binding1 String myField2; "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class Two {" + + " @Stereotype1 @Produces @Binding1 String myField1; "+ + " @Stereotype2 @Produces @Binding1 One myField2; "+ + " @Alternative @Produces @Binding1 Two myField3; "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class TestClass {" + + " @Inject @Binding1 int myField1; "+ + " @Inject @Binding1 String myField2; "+ + " @Inject @Binding1 One myField3; "+ + " @Inject @Binding1 Two myField4; "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Alternative "+ + "@Stereotype "+ + "public @interface Stereotype1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Alternative "+ + "@Stereotype "+ + "public @interface Stereotype2 {}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myField1")){ + checkProduction1( element , model ); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + checkProduction2( element , model); + } + else if ( element.getSimpleName().contentEquals("myField3")){ + checkProduction3( element , model); + } + else if ( element.getSimpleName().contentEquals("myField4")){ + checkProduction4( element , model); + } + } + + assert names.contains("myField1"); + assert names.contains("myField2"); + assert names.contains("myField3"); + assert names.contains("myField4"); + return null; + } + + }); + } + + protected void checkMixed1( VariableElement element, WebBeansModel model ) { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull( result ); + + assertEquals( DependencyInjectionResult.ResultKind.INJECTABLE_RESOLVED, result.getKind()); + assertTrue( result instanceof DependencyInjectionResult.InjectableResult ); + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + + Element injectable = ((DependencyInjectionResult.InjectableResult)result).getElement(); + assertTrue( injectable instanceof TypeElement ); + String name = ((TypeElement)injectable).getQualifiedName().toString(); + + assertEquals( "foo.Two", name ); + + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + + assertEquals( 0 , productions.size()); + assertEquals( 2 , typeElements.size()); + + boolean oneFound = false; + boolean twoFound = false; + TypeElement one = null; + TypeElement two = null; + for( TypeElement typeElement : typeElements ){ + String typeName = typeElement.getQualifiedName().toString(); + if ( "foo.One".equals(typeName)){ + oneFound = true; + one = typeElement; + } + if ( "foo.Two".equals( typeName)){ + twoFound = true; + two = typeElement; + } + } + + assertTrue( "myField2 defined in class foo.One should be available " + + "via ApplicableResult interface", oneFound ); + + assertTrue( "myField1 defined in class foo.Two should be available " + + "via ApplicableResult interface", twoFound ); + + assertTrue ( "myField2 in foo.One is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( one )); + assertTrue ( "myField1 in foo.Two is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( two )); + + assertTrue( "myField2 in foo.One should be disabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(one)); + assertFalse( "myField1 in foo.Two should be enabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(two)); + } + + protected void checkMixed2( VariableElement element, WebBeansModel model ) { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull( result ); + + assertEquals( DependencyInjectionResult.ResultKind.INJECTABLE_RESOLVED, result.getKind()); + assertTrue( result instanceof DependencyInjectionResult.InjectableResult ); + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + + Element injectable = ((DependencyInjectionResult.InjectableResult)result).getElement(); + assertTrue( injectable instanceof TypeElement ); + String name = ((TypeElement)injectable).getQualifiedName().toString(); + + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + + assertEquals( 0 , productions.size()); + assertEquals( 1 , typeElements.size()); + + assertEquals( "foo.Three", name ); + + assertEquals(injectable,typeElements.iterator().next()); + + assertTrue ( "foo.Three is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( injectable )); + } + + protected void checkProduction1( VariableElement element, + WebBeansModel model ) + { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull( result ); + + assertEquals( DependencyInjectionResult.ResultKind.INJECTABLE_RESOLVED, result.getKind()); + assertTrue( result instanceof DependencyInjectionResult.InjectableResult ); + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + + Element injectable = ((DependencyInjectionResult.InjectableResult)result).getElement(); + assertTrue( injectable instanceof VariableElement ); + String name = injectable.getSimpleName().toString(); + + assertEquals( "myField1", name ); + + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + + assertEquals( 1 , productions.size()); + assertEquals( 0 , typeElements.size()); + + assertEquals(injectable,productions.iterator().next()); + + assertTrue ( "myField1 defined in foo.One is not an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( injectable )); + } + + protected void checkProduction2( VariableElement element, + WebBeansModel model ) + { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull( result ); + + assertEquals( DependencyInjectionResult.ResultKind.INJECTABLE_RESOLVED, result.getKind()); + assertTrue( result instanceof DependencyInjectionResult.InjectableResult ); + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + + Element injectable = ((DependencyInjectionResult.InjectableResult)result).getElement(); + assertTrue( injectable instanceof VariableElement ); + String name = injectable.getSimpleName().toString(); + + assertEquals( "myField1", name ); + + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + + assertEquals( 2 , productions.size()); + assertEquals( 0 , typeElements.size()); + + boolean oneFound = false; + boolean twoFound = false; + Element one = null; + Element two = null; + for( Element field : productions ){ + String fieldName = field.getSimpleName().toString(); + if ( "myField2".equals(fieldName)){ + oneFound = true; + one = field; + } + if ( "myField1".equals( fieldName)){ + twoFound = true; + two = field; + } + } + + assertTrue( "myField2 defined in class foo.One should be available " + + "via ApplicableResult interface", oneFound ); + + assertTrue( "myField1 defined in class foo.Two should be available " + + "via ApplicableResult interface", twoFound ); + + assertTrue ( "myField2 in foo.One is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( one )); + assertTrue ( "myField1 in foo.Two is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( two )); + + assertTrue( "myField2 in foo.One should be disabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(one)); + assertFalse( "myField1 in foo.Two should be enabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(two)); + } + + protected void checkProduction3( VariableElement element, + WebBeansModel model ) + { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull( result ); + + assertEquals( DependencyInjectionResult.ResultKind.RESOLUTION_ERROR, result.getKind()); + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + + assertEquals( 1 , productions.size()); + assertEquals( 0 , typeElements.size()); + + Element resolved = productions.iterator().next(); + + assertEquals( "myField2" , resolved.getSimpleName().toString()); + + assertTrue ( "myField2 in foo.Two is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( resolved )); + + assertTrue( "myField2 should be disabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(resolved)); + + } + + protected void checkProduction4( VariableElement element, + WebBeansModel model ) + { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull( result ); + + assertEquals( DependencyInjectionResult.ResultKind.RESOLUTION_ERROR, result.getKind()); + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + + assertEquals( 1 , productions.size()); + assertEquals( 0 , typeElements.size()); + + Element resolved = productions.iterator().next(); + + assertEquals( "myField3" , resolved.getSimpleName().toString()); + + assertTrue ( "myField3 in foo.Two is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( resolved )); + + assertTrue( "myField3 should be disabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(resolved)); + } + + private void check2( VariableElement element, WebBeansModel model ) + { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull( result ); + + assertEquals( DependencyInjectionResult.ResultKind.INJECTABLE_RESOLVED, result.getKind()); + + assertTrue( result instanceof DependencyInjectionResult.InjectableResult ); + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + + Element injectable = ((DependencyInjectionResult.InjectableResult)result).getElement(); + + assertTrue( injectable instanceof TypeElement ); + String name = ((TypeElement) injectable).getQualifiedName().toString(); + + assertEquals( "foo.Two1", name ); + + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + + assertEquals( 0 , productions.size()); + assertEquals( 3 , typeElements.size()); + + boolean twoFound = false; + boolean fourFound = false; + boolean fiveFound = false; + TypeElement two = null; + TypeElement four = null; + TypeElement five = null; + for( TypeElement typeElement : typeElements ){ + String typeName = typeElement.getQualifiedName().toString(); + if ( "foo.Two1".equals(typeName)){ + twoFound = true; + two = typeElement; + } + if ( "foo.Four".equals( typeName)){ + fourFound = true; + four = typeElement; + } + if ( "foo.Five".equals( typeName)){ + fiveFound = true; + five = typeElement; + } + } + + assertTrue( "foo.Two1 should be available via ApplicableResult interface", + twoFound ); + assertTrue( "foo.Four should be available via ApplicableResult interface", + fourFound ); + assertTrue( "foo.Five should be available via ApplicableResult interface", + fiveFound ); + + assertFalse ( "foo.Two1 is not an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( two )); + assertTrue ( "foo.Four is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( four )); + assertTrue ( "foo.Five is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( five )); + + assertFalse( "foo.Two1 should be enabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(two)); + assertTrue( "foo.Four should be disabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(four)); + assertTrue( "foo.Five should be disabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(five)); + + } + + private void check1( VariableElement element, WebBeansModel model ) + { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull( result ); + + assertEquals( DependencyInjectionResult.ResultKind.INJECTABLE_RESOLVED, result.getKind()); + + assertTrue( result instanceof DependencyInjectionResult.InjectableResult ); + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + + Element injectable = ((DependencyInjectionResult.InjectableResult)result).getElement(); + + assertTrue( injectable instanceof TypeElement ); + String name = ((TypeElement) injectable).getQualifiedName().toString(); + + assertEquals( "foo.Two", name ); + + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + + assertEquals( 0 , productions.size()); + assertEquals( 2 , typeElements.size()); + + boolean twoFound = false; + boolean threeFound = false; + TypeElement two = null; + TypeElement three = null; + for( TypeElement typeElement : typeElements ){ + String typeName = typeElement.getQualifiedName().toString(); + if ( "foo.Two".equals(typeName)){ + twoFound = true; + two = typeElement; + } + if ( "foo.Three".equals( typeName)){ + threeFound = true; + three = typeElement; + } + } + assertTrue( "foo.Two should be available via ApplicableResult interface", + twoFound ); + assertTrue( "foo.Three should be available via ApplicableResult interface", + threeFound ); + + assertFalse( "foo.Two should be enabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(two)); + assertTrue( "foo.Three should be disabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(three)); + + assertFalse ( "foo.Two is not an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( two )); + assertTrue ( "foo.Three is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( three )); + } + + private void check3( VariableElement element, WebBeansModel model ) + { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull( result ); + + assertEquals( DependencyInjectionResult.ResultKind.INJECTABLE_RESOLVED, result.getKind()); + + assertTrue( result instanceof DependencyInjectionResult.InjectableResult ); + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + + Element injectable = ((DependencyInjectionResult.InjectableResult)result).getElement(); + + assertTrue( injectable instanceof TypeElement ); + String name = ((TypeElement) injectable).getQualifiedName().toString(); + + assertEquals( "foo.Two1", name ); + + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + + assertEquals( 0 , productions.size()); + assertEquals( 2 , typeElements.size()); + + boolean twoFound = false; + boolean fiveFound = false; + TypeElement two = null; + TypeElement five = null; + for( TypeElement typeElement : typeElements ){ + String typeName = typeElement.getQualifiedName().toString(); + if ( "foo.Two1".equals(typeName)){ + twoFound = true; + two = typeElement; + } + if ( "foo.Five".equals( typeName)){ + fiveFound = true; + five = typeElement; + } + } + assertTrue( "foo.Two1 should be available via ApplicableResult interface", + twoFound ); + assertTrue( "foo.Five should be available via ApplicableResult interface", + fiveFound ); + + assertFalse( "foo.Two1 should be enabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(two)); + assertTrue( "foo.Five should be disabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(five)); + + assertFalse ( "foo.Two1 is not an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( two )); + assertTrue ( "foo.Five is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( five )); + } + + private void checkEnabled1( VariableElement element, WebBeansModel model ) + { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull( result ); + + assertEquals( DependencyInjectionResult.ResultKind.INJECTABLE_RESOLVED, result.getKind()); + + assertTrue( result instanceof DependencyInjectionResult.InjectableResult ); + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + + Element injectable = ((DependencyInjectionResult.InjectableResult)result).getElement(); + + assertTrue( injectable instanceof TypeElement ); + String name = ((TypeElement) injectable).getQualifiedName().toString(); + + assertEquals( "foo.Three", name ); + + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + + assertEquals( 0 , productions.size()); + assertEquals( 1 , typeElements.size()); + + assertEquals("foo.Three", + typeElements.iterator().next().getQualifiedName().toString() ); + + assertFalse( "foo.Three should be enabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(injectable)); + + assertTrue ( "foo.Three is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( injectable )); + } + + private void checkEnabled2( VariableElement element, WebBeansModel model ) + { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull( result ); + + assertEquals( DependencyInjectionResult.ResultKind.RESOLUTION_ERROR, result.getKind()); + + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + + assertEquals( 0 , productions.size()); + assertEquals( 3 , typeElements.size()); + + boolean oneFound = false; + boolean fourFound = false; + boolean fiveFound = false; + TypeElement one = null; + TypeElement five = null; + TypeElement four = null; + for( TypeElement typeElement : typeElements ){ + String typeName = typeElement.getQualifiedName().toString(); + if ( "foo.One1".equals(typeName)){ + oneFound = true; + one = typeElement; + } + if ( "foo.Four".equals( typeName)){ + fourFound = true; + four = typeElement; + } + if ( "foo.Five".equals( typeName)){ + fiveFound = true; + five = typeElement; + } + } + + assertTrue( "foo.One1 should be available via ApplicableResult interface", + oneFound ); + assertTrue( "foo.Four should be available via ApplicableResult interface", + fourFound ); + assertTrue( "foo.Five should be available via ApplicableResult interface", + fiveFound ); + + assertFalse( "foo.Four should be enabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(four)); + assertFalse( "foo.Five should be enabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(five)); + assertTrue( "foo.One1 should be disabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(one)); + + assertTrue ( "foo.One1 is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( one )); + assertTrue ( "foo.Four is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( four )); + assertTrue ( "foo.Five is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( five )); + + } + + private void checkEnabled3( VariableElement element, WebBeansModel model ) + { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull( result ); + + assertEquals( DependencyInjectionResult.ResultKind.INJECTABLE_RESOLVED, result.getKind()); + + assertTrue( result instanceof DependencyInjectionResult.InjectableResult ); + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + + Element injectable = ((DependencyInjectionResult.InjectableResult)result).getElement(); + + assertTrue( injectable instanceof TypeElement ); + String name = ((TypeElement) injectable).getQualifiedName().toString(); + + assertEquals( "foo.Five", name ); + + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + + assertEquals( 0 , productions.size()); + assertEquals( 1 , typeElements.size()); + + assertEquals("foo.Five", + typeElements.iterator().next().getQualifiedName().toString() ); + + assertFalse( "foo.Five should be enabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(injectable)); + + assertTrue ( "foo.Five is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( injectable )); + } +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/AnyTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/AnyTest.java new file mode 100644 index 000000000000..a0dcedf877d8 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/AnyTest.java @@ -0,0 +1,242 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.impl.model.results.ResultImpl; + + +/** + * @author ads + * + */ +public class AnyTest extends CommonTestCase { + + public AnyTest( String testName ) { + super(testName); + } + + public void testSingleAny() throws IOException, InterruptedException{ + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {" + + " String value(); "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding2 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class SuperClass { " + + " @Produces String productionField = \"\"; "+ + " @Produces @foo.Binding2 int[] productionMethod() { return null; } "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@foo.Binding1(value=\"a\") @foo.Binding2 " + + "public class One extends SuperClass {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class TestClass {" + + " @Inject @Any One myField1; "+ + " @Inject @Any Two myField2; "+ + " @Inject @Any SuperClass myField3; "+ + " @Inject @Any String myField4; "+ + " @Inject @Any int[] myField5; "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "@foo.Binding2 " + + "public class Two extends SuperClass {}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myField1")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.One"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.Two"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + else if ( element.getSimpleName().contentEquals("myField3")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.One", "foo.Two", "foo.SuperClass"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + else if ( element.getSimpleName().contentEquals("myField4")){ + assertFindVariableResultInjectables((VariableElement)element, provider); + assertFindVariableResultProductionsVar((VariableElement)element, provider, "productionField"); + } + else if ( element.getSimpleName().contentEquals("myField5")){ + assertFindVariableResultInjectables((VariableElement)element, provider); + assertFindVariableResultProductions((VariableElement)element, provider, "productionMethod"); + } + } + + assert names.contains("myField1"); + assert names.contains("myField2"); + assert names.contains("myField3"); + assert names.contains("myField4"); + assert names.contains("myField5"); + return null; + } + }); + } + + + public void testAnyWithOther() throws IOException, InterruptedException{ + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomBinding.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface CustomBinding {" + + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@foo.CustomBinding " + + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "@foo.CustomBinding @Any" + + "public class Two {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class TestClass {" + + " @Inject @Any @foo.CustomBinding One myField1; "+ + " @Inject @Any Two myField2; "+ + "}" ); + + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myField1")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.One"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.Two"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + } + assert names.contains("myField1"); + assert names.contains("myField2"); + return null; + } + }); + + } + +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/CommonTestCase.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/CommonTestCase.java new file mode 100644 index 000000000000..d8d349191990 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/CommonTestCase.java @@ -0,0 +1,216 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; + +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.support.JavaSourceTestCase; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.parsing.api.indexing.IndexingManager; +import org.netbeans.modules.jakarta.web.beans.api.model.ModelUnit; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModelFactory; +import org.netbeans.modules.jakarta.web.beans.impl.model.results.ResultImpl; +import org.netbeans.modules.jakarta.web.beans.testutilities.CdiTestUtilities; + + +/** + * @author ads + * + */ +public class CommonTestCase extends JavaSourceTestCase { + + public CommonTestCase( String testName ) { + super(testName); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + myUtilities = new CdiTestUtilities(srcFO); + myUtilities.initAnnotations(); + /*URL url = FileUtil.getArchiveRoot(jakarta.faces.component.FacesComponent.class.getProtectionDomain(). + getCodeSource().getLocation()); + addCompileRoots( Collections.singletonList( url ));*/ + } + + public MetadataModel createBeansModel() throws IOException, InterruptedException { + IndexingManager.getDefault().refreshIndexAndWait(srcFO.getURL(), null); + return myUtilities.createBeansModel(); + } + + public TestWebBeansModelImpl createModelImpl() throws IOException { + return createModelImpl(false); + } + + public TestWebBeansModelImpl createModelImpl(boolean fullModel) throws IOException { + IndexingManager.getDefault().refreshIndexAndWait(srcFO.getURL(), null); + ModelUnit modelUnit = ModelUnit.create( + ClassPath.getClassPath(srcFO, ClassPath.BOOT), + ClassPath.getClassPath(srcFO, ClassPath.COMPILE), + ClassPath.getClassPath(srcFO, ClassPath.SOURCE), null); + return new TestWebBeansModelImpl(modelUnit, fullModel); + } + + protected void inform( String message ){ + System.out.println(message); + } + + protected void createQualifier(String name ) throws IOException{ + myUtilities.createQualifier(name); + } + + protected void createInterceptorBinding(String name ) throws IOException{ + myUtilities.createInterceptorBinding(name); + } + + public final void assertFindParameterResultInjectables(VariableElement element, + TestWebBeansModelProviderImpl provider, + String... injectables) { + DependencyInjectionResult result = provider.findParameterInjectable(element, null, new AtomicBoolean(false)); + assertResultInjectables(result, injectables); + } + + public final void assertFindParameterResultProductions(VariableElement element, + TestWebBeansModelProviderImpl provider, + String... injectables) { + DependencyInjectionResult result = provider.findParameterInjectable(element, null, new AtomicBoolean(false)); + assertResultProductions(result, injectables); + } + + public final void assertFindParameterResultProductionsVar(VariableElement element, + TestWebBeansModelProviderImpl provider, + String... injectables) { + DependencyInjectionResult result = provider.findParameterInjectable(element, null, new AtomicBoolean(false)); + assertResultProductions(result, true, injectables); + } + + public final void assertFindVariableResultInjectables(VariableElement element, + TestWebBeansModelProviderImpl provider, + String... injectables) { + DependencyInjectionResult result = provider.findVariableInjectable(element, null, new AtomicBoolean(false)); + assertResultInjectables(result, injectables); + } + + public final void assertFindVariableResultProductions(VariableElement element, + TestWebBeansModelProviderImpl provider, + String... injectables) { + DependencyInjectionResult result = provider.findVariableInjectable(element, null, new AtomicBoolean(false)); + assertResultProductions(result, injectables); + } + + public final void assertFindVariableResultProductionsVar(VariableElement element, + TestWebBeansModelProviderImpl provider, + String... injectables) { + DependencyInjectionResult result = provider.findVariableInjectable(element, null, new AtomicBoolean(false)); + assertResultProductions(result, true, injectables); + } + + public final void assertFindAllProductions(VariableElement element, + TestWebBeansModelProviderImpl provider, + String productionName , String enclosingClass ) { + DependencyInjectionResult result = provider.findVariableInjectable(element, null, new AtomicBoolean(false)); + assertResultAllProductions(result, productionName , enclosingClass ); + } + + public final void assertResultInjectables(DependencyInjectionResult result, String... injectables) { + assertNotNull(result); + assertTrue("not ResultImpl instance: "+result, result instanceof ResultImpl); + + Set typeElements = ((ResultImpl) result).getTypeElements(); + if (injectables == null) { + assertEquals("no injectables expected, but found: "+typeElements, 0, typeElements.size()); + } + assertTrue("number of injectables does not match: returned="+typeElements+" expected="+Arrays.asList(injectables), injectables.length == typeElements.size()); + Set set = new HashSet(); + for (TypeElement injactable : typeElements) { + set.add(injactable.getQualifiedName().toString()); + } + for (String inj : injectables) { + assertTrue("Result of typesafe resolution should contain " + inj + + " class definition in "+set, set.contains(inj)); + } + } + + public final void assertResultProductions(DependencyInjectionResult result, String... producers) { + assertResultProductions(result, false, producers); + } + + public final void assertResultProductions(DependencyInjectionResult result, boolean variable, String... producers) { + assertNotNull(result); + assertTrue("not ResultImpl instance: "+result, result instanceof ResultImpl); + + Set productions = ((ResultImpl) result).getProductions(); + if (producers == null) { + assertEquals("no producers expected, but found: "+productions, 0, productions.size()); + } + assertTrue("number of productions does not match: returned="+productions+" expected="+Arrays.asList(producers), producers.length == productions.size()); + Set set = new HashSet(); + for (Element injectable : productions) { + if (variable) { + assertTrue("injectable should be a production method," + " but found :" + + injectable.getKind(), injectable instanceof VariableElement); + } else { + assertTrue("injectable should be a production method," + " but found :" + + injectable.getKind(), injectable instanceof ExecutableElement); + } + set.add(injectable.getSimpleName().toString()); + } + for (String prod : producers) { + assertTrue("Result of typesafe resolution should contain " + prod + + " producer in "+set, set.contains(prod)); + } + } + + public final void assertResultAllProductions(DependencyInjectionResult result, String productionName , + String enclosingClass) + { + assertNotNull(result); + assertTrue("not ResultImpl instance: "+result, result instanceof ResultImpl); + + Set productions = ((ResultImpl) result).getProductions(); + if (productionName == null) { + assertEquals("no injectables expected, but found production element", 0, + productions.size()); + } + assertEquals( "Expected just one production element" , 1, productions.size() ); + Element production = productions.iterator().next(); + String name = production.getSimpleName().toString(); + + assertEquals("Production element name should be "+productionName,productionName, name); + Element parent = production.getEnclosingElement(); + assertTrue( parent instanceof TypeElement ); + String parentName = ((TypeElement)parent).getQualifiedName().toString(); + assertEquals( "Production enclosing class name should be "+enclosingClass, + enclosingClass , parentName); + } + + private CdiTestUtilities myUtilities; +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/CurrentTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/CurrentTest.java new file mode 100644 index 000000000000..3f56fc50be4e --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/CurrentTest.java @@ -0,0 +1,373 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + * Current = Default ( Current is name of Default from old specification ). + * + */ +public class CurrentTest extends CommonTestCase { + + public CurrentTest( String testName ) { + super(testName); + } + + public void testDefault() throws IOException, InterruptedException{ + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class SuperClass { " + + " @Produces String productionField = \"\"; "+ + " @Produces @Default int[] productionMethod() { return null; } "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Default " + + "public class One extends SuperClass {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class TestClass {" + + " @Inject @Default SuperClass myField1; "+ + " @Inject @Default String myField2; "+ + " @Inject int[] myField3; "+ + " @Inject One myField4; "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.inject.*; "+ + " @Named "+ + "public class Two extends SuperClass {}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myField1")){ + assertFindVariableResultInjectables(element, provider, "foo.SuperClass", "foo.One", "foo.Two"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + assertFindVariableResultInjectables(element, provider); + assertFindVariableResultProductionsVar(element, provider, "productionField"); + } + else if ( element.getSimpleName().contentEquals("myField3")){ + assertFindVariableResultInjectables(element, provider); + assertFindVariableResultProductions(element, provider, "productionMethod"); + } + else if ( element.getSimpleName().contentEquals("myField4")){ + assertFindVariableResultInjectables(element, provider, "foo.One"); + assertFindVariableResultProductions(element, provider); + } + } + assert names.contains("myField1"); + assert names.contains("myField2"); + assert names.contains("myField3"); + assert names.contains("myField4"); + return null; + } + }); + } + + public void testMixedDefault() throws IOException, InterruptedException{ + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {" + + " String value(); "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding2 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1(\"a\") "+ + "public class SuperClass { " + + " @Produces @Default @Binding1(\"b\") int[] productionMethod() { return null; } "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding2 " + + "public class One extends SuperClass {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class TestClass {" + + " @Inject One myField1; "+ + " @Inject @Default int[] myField2; "+ + " @Inject @Default SuperClass myField3; "+ + " @Inject @Default @Binding2 SuperClass myField4; "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.inject.*; "+ + " @Named "+ + "public class Two extends SuperClass {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1(\"a\") @Default "+ + "public class Three extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Four.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "@Binding2 @Default @Named "+ + "public class Four extends Two {}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myField1")){ + assertFindVariableResultInjectables(element, provider, "foo.Three"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + assertFindVariableResultInjectables(element, provider); + assertFindVariableResultProductions(element, provider, "productionMethod"); + } + else if ( element.getSimpleName().contentEquals("myField3")){ + assertFindVariableResultInjectables(element, provider, "foo.Four", "foo.Three", "foo.Two"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField4")){ + assertFindVariableResultInjectables(element, provider, "foo.Four"); + assertFindVariableResultProductions(element, provider); + } + } + assert names.contains("myField1"); + assert names.contains("myField2"); + assert names.contains("myField3"); + assert names.contains("myField4"); + return null; + } + }); + } + + public void testSpecializeInheritanceDefault() throws IOException, InterruptedException{ + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "@Inherited "+ + "public @interface Binding2 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class TestClass {" + + " @Inject @Default Two myField1; "+ + " @Inject One1 myField2; "+ + " @Inject @Default Two2 myField3; "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + "@Specializes "+ + "public class Two extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + "public class One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "public class Two1 extends One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding2 "+ + "public class One2 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class Two2 extends One2 {}" ); + + inform("start @Default inheritance and specializtion tests" ); + + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myField1")){ + assertFindVariableResultInjectables(element, provider); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + assertFindVariableResultInjectables(element, provider, "foo.Two1"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField3")){ + assertFindVariableResultInjectables(element, provider); + assertFindVariableResultProductions(element, provider); + } + } + assert names.contains("myField1"); + assert names.contains("myField2"); + assert names.contains("myField3"); + return null; + } + }); + } + +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/DecoratorTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/DecoratorTest.java new file mode 100644 index 000000000000..34ca746246ec --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/DecoratorTest.java @@ -0,0 +1,310 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class DecoratorTest extends CommonTestCase { + + public DecoratorTest( String testName ) { + super(testName); + } + + public void testSimple() throws IOException, InterruptedException { + createQualifier("Binding"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SimpleTest.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import jakarta.decorator.Decorator; "+ + "import jakarta.decorator.Delegate; "+ + "@Decorator "+ + "public class SimpleTest extends One {"+ + " @Inject @Delegate @Binding One myField; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SimpleTest1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import jakarta.decorator.Decorator; "+ + "import jakarta.decorator.Delegate; "+ + "@Decorator "+ + "public class SimpleTest1 extends One {"+ + " @Inject SimpleTest1( @Delegate One param ) {} "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "public class One {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "@Binding "+ + "public class Two extends One {}"); + + inform("start simple decorators tests"); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + checkDecorator(model, "foo.One" , "foo.SimpleTest1" ); + + checkDecorator(model, "foo.Two" , "foo.SimpleTest"); + + return null; + } + + }); + } + + public void testMultipleQualifiers() throws IOException, InterruptedException { + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.enterprise.util.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {" + + " String value(); "+ + " @Nonbinding String comment() default \"\"; "+ + "}"); + createQualifier("Binding2"); + createQualifier("Binding3"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SimpleTest.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import jakarta.decorator.Decorator; "+ + "import jakarta.decorator.Delegate; "+ + "@Decorator "+ + "public class SimpleTest extends One {"+ + " @Inject @Delegate @Binding1(value=\"a\", comment=\"a\") @Binding2 One myField; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SimpleTest1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import jakarta.decorator.Decorator; "+ + "import jakarta.decorator.Delegate; "+ + "@Decorator "+ + "public class SimpleTest1 extends One {"+ + " @Inject @Delegate @Binding2 One myField; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@Binding1(value=\"a\", comment=\"b\") "+ + "public class One {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding2 "+ + "@Specializes "+ + "public class Two extends One {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding2 @Binding3 "+ + "public class Three extends One {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Four.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1(value=\"b\", comment=\"a\") @Binding3 "+ + "public class Four extends One {}"); + + inform("start multiple decorators tests"); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + checkDecorator(model, "foo.One" ); + + checkDecorator(model, "foo.Two" , "foo.SimpleTest", "foo.SimpleTest1"); + + checkDecorator(model, "foo.Three" , "foo.SimpleTest1"); + + checkDecorator(model, "foo.Four" ); + + return null; + } + + }); + } + + /* + * @Default, @New , @Any + */ + public void testCornerCasesQualifiers() throws IOException, InterruptedException { + createQualifier("Binding1"); + createQualifier("Binding2"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SimpleTest.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import jakarta.decorator.Decorator; "+ + "import jakarta.decorator.Delegate; "+ + "@Decorator "+ + "public class SimpleTest extends One {"+ + " @Inject @Delegate @Binding1 @Default One myField; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SimpleTest1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import jakarta.decorator.Decorator; "+ + "import jakarta.decorator.Delegate; "+ + "@Decorator "+ + "public class SimpleTest1 extends One {"+ + " @Inject @Delegate One myField; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SimpleTest2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import jakarta.decorator.Decorator; "+ + "import jakarta.decorator.Delegate; "+ + "@Decorator "+ + "public class SimpleTest2 extends One {"+ + " @Inject @Delegate @Any Three myField; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SimpleTest3.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import jakarta.decorator.Decorator; "+ + "import jakarta.decorator.Delegate; "+ + "@Decorator "+ + "public class SimpleTest3 extends One {"+ + " @Inject @Delegate @New Four myField; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@Binding1 "+ + "public class One {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "public class Two extends One {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class Three extends One {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Four.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "@Default @Named "+ + "public class Four extends One {}"); + + inform("start multiple decorators tests"); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + checkDecorator(model, "foo.One" ); + + checkDecorator(model, "foo.Two" , "foo.SimpleTest", "foo.SimpleTest1"); + + checkDecorator(model, "foo.Three" , "foo.SimpleTest1", "foo.SimpleTest2"); + + checkDecorator(model, "foo.Four" , "foo.SimpleTest1", "foo.SimpleTest3"); + + return null; + } + + }); + } + + private void checkDecorator( WebBeansModel model, String className , + String... decorators ) + { + TypeMirror mirror = model.resolveType( className); + Element clazz = ((DeclaredType)mirror).asElement(); + TypeElement type = (TypeElement)clazz; + + Collection decoratorElements = model.getDecorators( type ); + assertEquals( "Class "+className+" should have exactly "+ + decorators.length+" decorator(s)", decorators.length , + decoratorElements.size()); + Set set =new HashSet(); + set.addAll( Arrays.asList( decorators )); + + Set fqns = new HashSet(); + for (TypeElement typeElement : decoratorElements) { + fqns.add( typeElement.getQualifiedName().toString()); + } + assertTrue( fqns.containsAll( set )); + } + +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/DelegateAssignabilityTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/DelegateAssignabilityTest.java new file mode 100644 index 000000000000..b22fc780e4a8 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/DelegateAssignabilityTest.java @@ -0,0 +1,330 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class DelegateAssignabilityTest extends CommonTestCase { + + public DelegateAssignabilityTest( String testName ) { + super(testName); + } + + public void testSimple() throws IOException, InterruptedException { + createQualifier("Binding"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SimpleTest.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import jakarta.decorator.Delegate; "+ + "public class SimpleTest extends Two {"+ + " @Inject @Delegate @Binding One myField; "+ + " @Inject void initMethod(@Delegate @Binding One param) {} " + + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@Binding "+ + "public class One {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "public class Two extends One {}"); + + inform("start delegate types tests"); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.SimpleTest" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if (element instanceof VariableElement) { + injectionPoints.add( (VariableElement)element ); + } + else if ( element instanceof ExecutableElement && + element.getSimpleName().contentEquals("initMethod")){ + injectionPoints.add( + ((ExecutableElement)element).getParameters().get(0)); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add(element.getSimpleName().toString()); + if ( element.getSimpleName().contentEquals("myField")){ + assertFindVariableResultInjectables(element, provider, "foo.One"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("param")){ + assertFindParameterResultInjectables(element, provider, "foo.One"); + assertFindParameterResultProductions(element, provider); + } + } + + assertTrue( names.contains("myField")); + assertTrue( names.contains("param")); + return null; + } + }); + } + + public void testRaw() throws IOException, InterruptedException { + createQualifier("Binding"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/RawTest.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import jakarta.decorator.Delegate; "+ + "public class RawTest extends Generic {"+ + " @Inject @Delegate @Binding Generic myField; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic.java", + "package foo; " + + "public class Generic {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class Two extends One {" + + " @Produces @Binding Generic productionField =null; " + + "}"); + + inform("start raw delegate types tests"); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.RawTest" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if (element instanceof VariableElement) { + injectionPoints.add( (VariableElement)element ); + } + } + boolean test = false; + for( VariableElement element : injectionPoints ){ + if ( element.getSimpleName().contentEquals("myField")){ + test = true; + assertFindVariableResultInjectables(element, provider); + assertFindVariableResultProductionsVar(element, provider, + "productionField"); + } + } + assertTrue( test); + return null; + } + }); + } + + public void testCommon() throws IOException, InterruptedException { + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding {" + + " String value(); "+ + "}"); + + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import jakarta.decorator.Delegate; "+ + "public class TestClass extends Generic2 {" + + " @Inject @Delegate @Binding(\"a\") Generic myField1; "+ + " @Inject @Delegate @Binding(\"b\") Generic myField2; "+ + " @Inject @Delegate @Binding(\"c\") Generic myField3; "+ + " @Inject @Delegate @Binding(\"b\") Generic myField4; "+ + " @Inject @Delegate @Binding(\"d\") Generic4 myField5; "+ + " @Inject @Delegate @Binding(\"e\") Generic5 myField6; "+ + " @Inject @Delegate @Binding(\"d\") Generic4 myField7; "+ + " @Inject @Delegate @Binding(\"d\") Generic myField8; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic.java", + "package foo; " + + " @Binding(\"a\") "+ + "public class Generic {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic1.java", + "package foo; " + + " @Binding(\"b\") "+ + "public class Generic1 extends Generic {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@Binding(\"a\") "+ + "public class One {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "public class Two extends One {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "public class Three extends One {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic2.java", + "package foo; " + + " @Binding(\"b\") "+ + "public class Generic2 extends Generic {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic3.java", + "package foo; " + + " @Binding(\"c\") "+ + "public class Generic3 extends Generic2 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic4.java", + "package foo; " + + " @Binding(\"d\") "+ + "public class Generic4 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic5.java", + "package foo; " + + " @Binding(\"e\") "+ + "public class Generic5 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic6.java", + "package foo; " + + " @Binding(\"d\") "+ + "public class Generic6 extends Generic4 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic7.java", + "package foo; " + + " @Binding(\"d\") "+ + "public class Generic7 extends Generic {}"); + + inform("start parametrizied delegate types tests"); + + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if (element instanceof VariableElement) { + injectionPoints.add( (VariableElement)element ); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myField1")){ + assertFindVariableResultInjectables(element, provider); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + assertFindVariableResultInjectables(element, provider, "foo.Generic2"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField3")){ + assertFindVariableResultInjectables(element, provider, "foo.Generic3"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField4")){ + assertFindVariableResultInjectables(element, provider, "foo.Generic1"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField5")){ + assertFindVariableResultInjectables(element, provider, "foo.Generic4", + "foo.Generic6" ); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField6")){ + assertFindVariableResultInjectables(element, provider, "foo.Generic5"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField7")){ + assertFindVariableResultInjectables(element, provider, "foo.Generic6"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField8")){ + assertFindVariableResultInjectables(element, provider, "foo.Generic7"); + assertFindVariableResultProductions(element, provider); + } + } + assert names.contains("myField1"); + assert names.contains("myField2"); + assert names.contains("myField3"); + assert names.contains("myField4"); + assert names.contains("myField5"); + assert names.contains("myField6"); + assert names.contains("myField7"); + assert names.contains("myField8"); + return null; + } + }); + } +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/DisabledBeansTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/DisabledBeansTest.java new file mode 100644 index 000000000000..907aa6421a3d --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/DisabledBeansTest.java @@ -0,0 +1,1068 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.Name; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class DisabledBeansTest extends CommonTestCase { + + public DisabledBeansTest( String testName ) { + super(testName); + } + + public void testSingeAlternative() throws IOException{ + TestUtilities.copyStringToFileObject(srcFO, "beans.xml", + " " + + "" + + "" + + "foo.One "+ + "foo.One1 "+ + "foo.Stereotype1 "+ + " " + + ""); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {}"); + + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + "@Alternative "+ + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "@Binding1 "+ + "public class Two extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Alternative "+ + "@Binding1 "+ + "public class One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two1.java", + "package foo; " + + "@Binding1 "+ + "public class Two1 extends One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + " @Stereotype1 "+ + "public class Three extends One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Alternative "+ + "@Stereotype "+ + "public @interface Stereotype1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class TestClass {" + + " @Inject @Binding1 One myField1; "+ + " @Inject @Binding1 One1 myField2; "+ + "}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myField1")){ + checkAlternative1( element , model ); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + checkAlternative2( element , model); + } + } + + assert names.contains("myField1"); + assert names.contains("myField2"); + return null; + } + }); + } + + public void testSpecializes() throws IOException{ + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {}"); + + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "public class Two extends One {}" ); + + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "public class Three extends Two {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + "public class One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Alternative "+ + "@Specializes "+ + "public class Two1 extends One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + "public class One2 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "@Alternative "+ + "public class Two2 extends One2 {}" ); + + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "public class Three2 extends Two2 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class TestClass {" + + " @Inject @Binding1 One myField1; "+ + " @Inject @Binding1 One1 myField2; "+ + " @Inject @Binding1 One2 myField3; "+ + "}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myField1")){ + checkSpecializes1( element , model ); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + checkSpecializes2( element , model); + } + else if ( element.getSimpleName().contentEquals("myField3")){ + checkSpecializes3( element , model); + } + } + + assert names.contains("myField1"); + assert names.contains("myField2"); + assert names.contains("myField3"); + return null; + } + }); + } + + public void testProxyability() throws IOException{ + createQualifier("Binding1"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface.java", + "package foo; " + + "public interface Iface {" + + " void method(); "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + "public final class One implements Iface {" + + " public final void method() {} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.enterprise.context.ApplicationScoped; "+ + "@Binding1 "+ + "@ApplicationScoped "+ + "public final class Two implements Iface {" + + " public void method() {} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.enterprise.context.SessionScoped; "+ + "@Binding1 "+ + "@SessionScoped "+ + "public class Three implements Iface {" + + " public final void method() {} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Four.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.enterprise.context.RequestScoped; "+ + "@Binding1 "+ + "@RequestScoped "+ + "public class Four implements Iface {" + + " private Four() {} "+ + " public Four( int arg ) {} "+ + " public void method() {} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class TestClass {" + + " @Inject @Binding1 Iface myField1; "+ + "}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myField1")){ + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + assertNotNull( result ); + assertEquals(DependencyInjectionResult.ResultKind.INJECTABLE_RESOLVED , + result.getKind() ); + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + assertTrue( result instanceof DependencyInjectionResult.InjectableResult ); + assertEquals(4 , ((DependencyInjectionResult.ApplicableResult)result). + getTypeElements().size()); + Element injectable = ((DependencyInjectionResult.InjectableResult)result).getElement(); + assertTrue( injectable instanceof TypeElement ); + Name qualifiedName = ((TypeElement)injectable).getQualifiedName(); + assertEquals("Injectable element should be foo.One", + "foo.One", qualifiedName.toString()); + } + } + assert names.contains("myField1"); + return null; + } + }); + }; + + public void testNotManagedBeans() throws IOException{ + createQualifier("Binding1"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class One {" + + "@Binding1 "+ + " public class SubClass1 extends One {} "+ + "@Binding1 "+ + " public static class SubClass2 extends One {} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + "@jakarta.decorator.Decorator "+ + "public abstract class Two {" + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + "public abstract class Three extends Two {" + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Four.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + "public class Four implements jakarta.enterprise.inject.spi.Extension {" + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Five.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + "public class Five {" + + " Five( String arg ) {} "+ + " public Five() {} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Six.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + "public class Six extends Five{" + + " public Six( int arg ) {} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Seven.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "@Binding1 "+ + "public class Seven extends Five {" + + " @Inject "+ + " public Seven( int arg1, String arg2 ) { } "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class TestClass {" + + " @Inject @Binding1 One myField1; "+ + " @Inject @Binding1 Two myField2; "+ + " @Inject @Binding1 Four myField3; "+ + " @Inject @Binding1 Five myField4; "+ + "}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myField1")){ + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + assertNotNull( result ); + assertEquals(DependencyInjectionResult.ResultKind.INJECTABLE_RESOLVED , + result.getKind() ); + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + assertTrue( result instanceof DependencyInjectionResult.InjectableResult ); + assertEquals(2 , ((DependencyInjectionResult.ApplicableResult)result). + getTypeElements().size()); + Element injectable = ((DependencyInjectionResult.InjectableResult)result).getElement(); + assertTrue( injectable instanceof TypeElement ); + Name qualifiedName = ((TypeElement)injectable).getQualifiedName(); + assertEquals("Injectable element should be foo.One.SubClass2", + "foo.One.SubClass2", qualifiedName.toString()); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + assertNotNull( result ); + assertEquals(DependencyInjectionResult.ResultKind.INJECTABLE_RESOLVED , + result.getKind() ); + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + assertEquals(2 , ((DependencyInjectionResult.ApplicableResult)result). + getTypeElements().size()); + Element injectable = ((DependencyInjectionResult.InjectableResult)result).getElement(); + assertTrue( injectable instanceof TypeElement ); + Name qualifiedName = ((TypeElement)injectable).getQualifiedName(); + assertEquals("Injectable element should be foo.Two", + "foo.Two", qualifiedName.toString()); + } + else if ( element.getSimpleName().contentEquals("myField3")){ + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + assertNotNull( result ); + assertEquals(DependencyInjectionResult.ResultKind.RESOLUTION_ERROR , + result.getKind() ) ; + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + int size = ((DependencyInjectionResult.ApplicableResult)result). + getTypeElements().size(); + assertEquals("There should be one element which is" + + " not managed bean", 1 , size); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + assertNotNull( result ); + assertEquals(DependencyInjectionResult.ResultKind.RESOLUTION_ERROR , + result.getKind() ); + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + assertEquals(3 , ((DependencyInjectionResult.ApplicableResult)result). + getTypeElements().size()); + + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result). + getTypeElements(); + boolean fiveFound = false; + boolean sixFound = false; + boolean sevenFound = false; + DependencyInjectionResult.ApplicableResult applicableResult = + (DependencyInjectionResult.ApplicableResult)result; + for (TypeElement typeElement : typeElements) { + String name = typeElement.getQualifiedName().toString(); + if ( "foo.Five".equals(name)){ + assertFalse ( "foo.Five should be enabled", + applicableResult.isDisabled(typeElement)); + fiveFound =true; + } + else if ( "foo.Six".equals(name)){ + assertTrue ( "foo.Six should be disabled", + applicableResult.isDisabled(typeElement)); + sixFound =true; + } + else if ( "foo.Seven".equals(name)){ + assertFalse ( "foo.Seven should be enabled", + applicableResult.isDisabled(typeElement)); + sevenFound =true; + } + } + assertTrue( "foo.Five should be in the list of eligible " + + "for injectoin elements", fiveFound ); + assertTrue( "foo.Seven should be in the list of eligible " + + "for injectoin elements", sevenFound ); + assertTrue( "foo.Six should be in the result", sevenFound ); + } + } + + assert names.contains("myField1"); + assert names.contains("myField2"); + assert names.contains("myField3"); + assert names.contains("myField4"); + return null; + } + }); + } + + public void testVariousDisableConditions() throws IOException{ + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {}"); + + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Alternative "+ + "public class One {" + + " @Produces @Binding1 int myField; "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.enterprise.context.ApplicationScoped; "+ + "@Binding1 "+ + "@ApplicationScoped "+ + "public final class Two implements Iface {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + "public interface Iface {}" ); + + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + "public class Three extends Two {" + + " private Three(){} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class TestClass {" + + " @Inject @Binding1 int myField1; "+ + " @Inject @Binding1 Iface myField2; "+ + "}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myField1")){ + checkVarious1( element , model ); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + checkVarious2( element , model); + } + } + + assert names.contains("myField1"); + assert names.contains("myField2"); + return null; + } + }); + } + + /* + * myField is disabled because it is inside disabled alternative bean. + */ + private void checkVarious1( VariableElement element, WebBeansModel model ) + { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull( result ); + + assertEquals( DependencyInjectionResult.ResultKind.RESOLUTION_ERROR, result.getKind()); + + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + + assertEquals( 1 , productions.size()); + assertEquals( 0 , typeElements.size()); + + Element production = productions.iterator().next(); + + assertTrue( production instanceof VariableElement ); + + assertEquals("myField", production.getSimpleName().toString()); + + assertFalse ( "production field myField is not an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( production )); + + assertTrue( "production field myField should be disabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(production)); + } + + /* + * All three types are disabled here. + * - Iface is not a bean . It is interface . So it can't be available as + * result of typesafe resolution + * - Two is final. So it is unproxyable. + * - Three has private CTOR . It is also unrpoxyable. + */ + private void checkVarious2( VariableElement element, WebBeansModel model ) + { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull( result ); + + assertEquals( DependencyInjectionResult.ResultKind.RESOLUTION_ERROR, result.getKind()); + + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + + assertEquals( 0 , productions.size()); + assertEquals( 3 , typeElements.size()); + + boolean twoFound = false; + boolean ifaceFound = false; + boolean threeFound = false; + TypeElement two = null; + TypeElement iface = null; + TypeElement three = null; + for( TypeElement typeElement : typeElements ){ + String typeName = typeElement.getQualifiedName().toString(); + if ( "foo.Two".equals(typeName)){ + twoFound = true; + two = typeElement; + } + if ( "foo.Iface".equals( typeName)){ + ifaceFound = true; + iface = typeElement; + } + if ( "foo.Three".equals( typeName)){ + threeFound = true; + three = typeElement; + } + } + + assertTrue( "foo.Two should be available via ApplicableResult interface", + twoFound ); + assertTrue( "foo.Iface should be available via ApplicableResult interface", + ifaceFound ); + assertTrue( "foo.Three should be available via ApplicableResult interface", + threeFound ); + + assertFalse ( "foo.Two is not an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( two )); + assertFalse ( "foo.One2 is not an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( iface )); + assertFalse ( "foo.Three2 is not an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( three )); + + assertTrue( "foo.Two2 should be disabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(two)); + assertTrue( "foo.One2 should be disabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(iface)); + assertTrue( "foo.Three2 should be disabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(three)); + } + + private void checkSpecializes3( VariableElement element, + WebBeansModel model ) + { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull( result ); + + assertEquals( DependencyInjectionResult.ResultKind.INJECTABLE_RESOLVED, result.getKind()); + + assertTrue( result instanceof DependencyInjectionResult.InjectableResult ); + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + + Element injectable = ((DependencyInjectionResult.InjectableResult)result).getElement(); + + assertTrue( injectable instanceof TypeElement ); + String name = ((TypeElement) injectable).getQualifiedName().toString(); + + assertEquals( "foo.Three2", name ); + + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + + assertEquals( 0 , productions.size()); + assertEquals( 3 , typeElements.size()); + + boolean twoFound = false; + boolean oneFound = false; + boolean threeFound = false; + TypeElement two = null; + TypeElement one = null; + TypeElement three = null; + for( TypeElement typeElement : typeElements ){ + String typeName = typeElement.getQualifiedName().toString(); + if ( "foo.Two2".equals(typeName)){ + twoFound = true; + two = typeElement; + } + if ( "foo.One2".equals( typeName)){ + oneFound = true; + one = typeElement; + } + if ( "foo.Three2".equals( typeName)){ + threeFound = true; + three = typeElement; + } + } + + assertTrue( "foo.Two2 should be available via ApplicableResult interface", + twoFound ); + assertTrue( "foo.One2 should be available via ApplicableResult interface", + oneFound ); + assertTrue( "foo.Three2 should be available via ApplicableResult interface", + threeFound ); + + assertTrue ( "foo.Two2 is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( two )); + assertFalse ( "foo.One2 is not an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( one )); + assertFalse ( "foo.Three2 is not an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( three )); + + assertTrue( "foo.Two2 should be disabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(two)); + assertTrue( "foo.One2 should be enabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(one)); + assertFalse( "foo.Three2 should be disabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(three)); + } + + private void checkSpecializes2( VariableElement element, + WebBeansModel model ) + { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull( result ); + + assertEquals( DependencyInjectionResult.ResultKind.INJECTABLE_RESOLVED, result.getKind()); + + assertTrue( result instanceof DependencyInjectionResult.InjectableResult ); + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + + Element injectable = ((DependencyInjectionResult.InjectableResult)result).getElement(); + + assertTrue( injectable instanceof TypeElement ); + String name = ((TypeElement) injectable).getQualifiedName().toString(); + + assertEquals( "foo.One1", name ); + + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + + assertEquals( 0 , productions.size()); + assertEquals( 2 , typeElements.size()); + + boolean twoFound = false; + boolean oneFound = false; + TypeElement two = null; + TypeElement one = null; + for( TypeElement typeElement : typeElements ){ + String typeName = typeElement.getQualifiedName().toString(); + if ( "foo.Two1".equals(typeName)){ + twoFound = true; + two = typeElement; + } + if ( "foo.One1".equals( typeName)){ + oneFound = true; + one = typeElement; + } + } + assertTrue( "foo.Two1 should be available via ApplicableResult interface", + twoFound ); + assertTrue( "foo.One1 should be available via ApplicableResult interface", + oneFound ); + + assertTrue( "foo.Two1 should be disnabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(two)); + assertFalse( "foo.One1 should be enabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(one)); + + assertTrue ( "foo.Two1 is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( two )); + assertFalse( "foo.One1 is not an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( one )); + } + + private void checkSpecializes1( VariableElement element, WebBeansModel model ) + { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull(result); + + assertEquals(DependencyInjectionResult.ResultKind.INJECTABLE_RESOLVED, result.getKind()); + + assertTrue(result instanceof DependencyInjectionResult.InjectableResult); + assertTrue(result instanceof DependencyInjectionResult.ApplicableResult); + assertTrue(result instanceof DependencyInjectionResult.ResolutionResult); + + Element injectable = ((DependencyInjectionResult.InjectableResult)result).getElement(); + + assertTrue(injectable instanceof TypeElement); + String name = ((TypeElement) injectable).getQualifiedName().toString(); + + assertEquals("foo.Three", name); + + Set productions = ((DependencyInjectionResult.ApplicableResult) result) + .getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult) result) + .getTypeElements(); + + assertEquals(0, productions.size()); + assertEquals(3, typeElements.size()); + + boolean twoFound = false; + boolean oneFound = false; + boolean threeFound = false; + TypeElement two = null; + TypeElement one = null; + TypeElement three = null; + for (TypeElement typeElement : typeElements) { + String typeName = typeElement.getQualifiedName().toString(); + if ("foo.Two".equals(typeName)) { + twoFound = true; + two = typeElement; + } + if ("foo.One".equals(typeName)) { + oneFound = true; + one = typeElement; + } + if ("foo.Three".equals(typeName)) { + threeFound = true; + three = typeElement; + } + } + assertTrue("foo.Two should be available via ApplicableResult interface", + twoFound); + assertTrue("foo.One should be available via ApplicableResult interface", + oneFound); + assertTrue("foo.Three should be available via ApplicableResult interface", + threeFound); + + assertTrue("foo.One should be disabled", + ((DependencyInjectionResult.ApplicableResult) result).isDisabled(one)); + assertTrue("foo.Two should be disabled", + ((DependencyInjectionResult.ApplicableResult) result).isDisabled(two)); + assertFalse("foo.Three should be enabled", + ((DependencyInjectionResult.ApplicableResult) result).isDisabled(three)); + } + + private void checkAlternative2( VariableElement element, + WebBeansModel model ) + { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull( result ); + + assertEquals( DependencyInjectionResult.ResultKind.RESOLUTION_ERROR, result.getKind()); + + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + + assertEquals( 0 , productions.size()); + assertEquals( 3 , typeElements.size()); + + boolean twoFound = false; + boolean oneFound = false; + boolean threeFound = false; + TypeElement two = null; + TypeElement one = null; + TypeElement three = null; + for( TypeElement typeElement : typeElements ){ + String typeName = typeElement.getQualifiedName().toString(); + if ( "foo.Two1".equals(typeName)){ + twoFound = true; + two = typeElement; + } + if ( "foo.One1".equals( typeName)){ + oneFound = true; + one = typeElement; + } + if ( "foo.Three".equals( typeName)){ + threeFound = true; + three = typeElement; + } + } + + assertTrue( "foo.Two1 should be available via ApplicableResult interface", + twoFound ); + assertTrue( "foo.One1 should be available via ApplicableResult interface", + oneFound ); + assertTrue( "foo.Three should be available via ApplicableResult interface", + threeFound ); + + assertFalse ( "foo.Two1 is not an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( two )); + assertTrue ( "foo.One1 is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( one )); + assertTrue ( "foo.Three is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( three )); + + assertFalse( "foo.Two1 should be enabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(two)); + assertFalse( "foo.One1 should be enabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(one)); + assertFalse( "foo.Three should be enabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(three)); + } + + private void checkAlternative1( VariableElement element, + WebBeansModel model ) + { + DependencyInjectionResult result = model.lookupInjectables(element, null, new AtomicBoolean(false)); + + assertNotNull( result ); + + assertEquals( DependencyInjectionResult.ResultKind.INJECTABLE_RESOLVED, result.getKind()); + + assertTrue( result instanceof DependencyInjectionResult.InjectableResult ); + assertTrue( result instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( result instanceof DependencyInjectionResult.ResolutionResult ); + + Element injectable = ((DependencyInjectionResult.InjectableResult)result).getElement(); + + assertTrue( injectable instanceof TypeElement ); + String name = ((TypeElement) injectable).getQualifiedName().toString(); + + assertEquals( "foo.One", name ); + + Set productions = ((DependencyInjectionResult.ApplicableResult)result).getProductions(); + Set typeElements = ((DependencyInjectionResult.ApplicableResult)result).getTypeElements(); + + assertEquals( 0 , productions.size()); + assertEquals( 2 , typeElements.size()); + + boolean twoFound = false; + boolean oneFound = false; + TypeElement two = null; + TypeElement one = null; + for( TypeElement typeElement : typeElements ){ + String typeName = typeElement.getQualifiedName().toString(); + if ( "foo.Two".equals(typeName)){ + twoFound = true; + two = typeElement; + } + if ( "foo.One".equals( typeName)){ + oneFound = true; + one = typeElement; + } + } + assertTrue( "foo.Two should be available via ApplicableResult interface", + twoFound ); + assertTrue( "foo.One should be available via ApplicableResult interface", + oneFound ); + + assertFalse( "foo.Two should be enabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(two)); + assertFalse( "foo.One should be disabled", + ((DependencyInjectionResult.ApplicableResult)result).isDisabled(one)); + + assertFalse ( "foo.Two is not an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( two )); + assertTrue ( "foo.One is an Alternative", + ((DependencyInjectionResult.ResolutionResult)result).isAlternative( one )); + } + +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/EventTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/EventTest.java new file mode 100644 index 000000000000..11e3ec1d2984 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/EventTest.java @@ -0,0 +1,669 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Name; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelException; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class EventTest extends CommonTestCase { + + public EventTest(String testName ){ + super( testName); + } + + public void testSimple () throws MetadataModelException, IOException, + InterruptedException + { + createQualifier("Binding"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/EventObject.java", + "package foo; " + + "public class EventObject { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.inject.*; "+ + "import jakarta.enterprise.event.Event; "+ + "public class Clazz {" + + " @Inject @foo.Binding Event event; " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; "+ + "public class TestClass {" + + " public void eventObserver( @Observes @foo.Binding EventObject event ) {}" + + "} "); + + inform("start simple event test"); + + MetadataModel metaModel = createBeansModel() ; + metaModel.runReadAction(new MetadataModelAction(){ + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List methods = ElementFilter.methodsIn( children ); + + assertEquals( 1, methods.size()); + ExecutableElement method = methods.get(0); + assertEquals( method.getSimpleName().toString(), "eventObserver"); + List events = model.getEventInjectionPoints( method, + (DeclaredType)mirror ); + assertEquals( "Should be exactly one event injection , but found " + + events.size() +" events", 1, events.size()); + VariableElement var = events.get(0); + assertNotNull( var ); + String name = var.getSimpleName().toString(); + assertEquals( "event" , name ); + return null; + } + }); + } + + public void testCommon () throws MetadataModelException, IOException, + InterruptedException + { + createQualifier("Binding"); + createQualifier("Binding1"); + createQualifier("Binding2"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperObject.java", + "package foo; " + + "public class SuperObject { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface.java", + "package foo; " + + "public interface Iface { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/EventObject.java", + "package foo; " + + "public class EventObject extends SuperObject implements Iface { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.inject.*; " + + "import jakarta.enterprise.event.Event; " + + "public class Clazz {" + + " @Inject @foo.Binding @foo.Binding2 Event event; " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO,"foo/TestClass1.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; " + + "public class TestClass1 {" + + " public void eventObserver( @Observes @foo.Binding @foo.Binding2 SuperObject event ) {}" + + " public void method( @foo.Binding @foo.Binding2 EventObject event ) {}" + + "} "); + + TestUtilities.copyStringToFileObject(srcFO,"foo/TestClass2.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; " + + "public class TestClass2 {" + + " public void eventObserver( @Observes @foo.Binding @foo.Binding2 Iface event ) {}" + + " public void notEventObserver( @Observes @foo.Binding @foo.Binding1 EventObject event ) {}" + + "} "); + + inform("start common event test"); + + MetadataModel metaModel = createBeansModel(); + metaModel.runReadAction(new MetadataModelAction() { + + public Void run( WebBeansModel model ) throws Exception { + commonCheck(model, "foo.TestClass1", false); + commonCheck(model, "foo.TestClass2", true); + return null; + } + + }); + } + + public void testMembersQualifier () throws MetadataModelException, IOException, + InterruptedException + { + createQualifier("Binding"); + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {" + + " String value(); "+ + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.enterprise.util.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.enterprise.util.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding2 {" + + " @Nonbinding String comment() default \"\"; "+ + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperObject1.java", + "package foo; " + + "public class SuperObject1 { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperObject2.java", + "package foo; " + + "public class SuperObject2 extends SuperObject1 { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface1.java", + "package foo; " + + "public interface Iface1 { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface2.java", + "package foo; " + + "public interface Iface2 extends Iface1 { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/EventObject.java", + "package foo; " + + "public class EventObject extends SuperObject2 implements Iface2 { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.inject.*; " + + "import jakarta.enterprise.event.Event; " + + "public class Clazz {" + + " @Inject @foo.Binding2(comment=\"c\") @foo.Binding1(value=\"a\") Event event; " + + " @Inject @foo.Binding @foo.Binding1(value=\"b\") Event event1; " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO,"foo/TestClass1.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; " + + "public class TestClass1 {" + + " public void eventObserver( @Observes @foo.Binding " + + "@foo.Binding1(value=\"a\") @foo.Binding2(comment=\"other\")" + + " SuperObject1 event ) {}" + + " public void eventObserver1( @Observes " + + "@foo.Binding2(comment=\"any\") @foo.Binding1(value=\"a\") Iface1 event ) {}" + + "} "); + + TestUtilities.copyStringToFileObject(srcFO,"foo/TestClass2.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; " + + "public class TestClass2 {" + + " public void notEventObserver( @Observes @foo.Binding " + + "@foo.Binding2(comment=\"\") @foo.Binding1(value=\"b\") Iface2 event ) {}" + + " public void notEventObserver2( @Observes @foo.Binding " + + "@foo.Binding1(value=\"a\") EventObject event ) {}" + + " public void notEventObserver3( @Observes @foo.Binding " + + "@foo.Binding1(value=\"b\") Iface1 event ) {}" + + "} "); + + inform("start event test with binding members"); + + MetadataModel metaModel = createBeansModel(); + metaModel.runReadAction(new MetadataModelAction() { + + public Void run( WebBeansModel model ) throws Exception { + unmatchedObserversCheck(model, 3); + + bindingMembersCheck( model ); + + return null; + } + }); + } + + public void testAny()throws MetadataModelException, IOException, + InterruptedException + { + createQualifier("Binding"); + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {" + + " String value(); "+ + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperObject.java", + "package foo; " + + "public class SuperObject { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface.java", + "package foo; " + + "public class Iface { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/EventObject.java", + "package foo; " + + "public class EventObject extends SuperObject implements Iface { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/EventObject1.java", + "package foo; " + + "public class EventObject1 { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.inject.*; " + +"import jakarta.enterprise.inject.Any; " + + "import jakarta.enterprise.event.Event; " + + "public class Clazz {" + + " @Inject @Any Event event; " + + " @Inject Event event1; " + + " @Inject @Binding1(value=\"a\") @Any Event event2; " + + " @Inject @Binding @Any Event event3; " + + " @Inject @Binding Event event4; " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO,"foo/TestClass1.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; "+ + "import jakarta.enterprise.inject.Any; " + + "public class TestClass1 {" + + " public void eventObserver( @Observes SuperObject event ) {}" + + " public void eventObserver1( @Observes @Any Iface1 event ) {}" + + " public void eventObserver2( @Observes @Binding1(value=\"a\") EventObject event ) {}" + + " public void eventObserver3( @Observes @Binding1(value=\"a\") @Any EventObject event ) {}" + + "} "); + + TestUtilities.copyStringToFileObject(srcFO,"foo/TestClass2.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; "+ + "import jakarta.enterprise.inject.Any; " + + "public class TestClass2 {" + + " public void notEventObserver( @Observes @Any EventObject1 event ) {}" + + " public void notEventObserver1( @Observes EventObject1 event ) {}" + + "} "); + + inform("start @Any event test"); + + MetadataModel metaModel = createBeansModel(); + metaModel.runReadAction(new MetadataModelAction() { + + public Void run( WebBeansModel model ) throws Exception { + unmatchedObserversCheck(model, 2); + + anyEventsCheck( model ); + return null; + } + + }); + + } + + public void testRawParameterizedAssignability()throws MetadataModelException, + IOException, InterruptedException +{ + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding {" + + " String value(); "+ + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/EventObject.java", + "package foo; " + + "public class EventObject extends SuperObject { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperObject.java", + "package foo; " + + "public class SuperObject { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/ChildObject.java", + "package foo; " + + "public class ChildObject extends EventObject { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.inject.*; " + +"import jakarta.enterprise.inject.Any; " + + "import jakarta.enterprise.event.Event; " + + "import java.util.List; " + + "import java.util.Set; " + + "import java.util.Collection; " + + "public class Clazz {" + + " @Inject @Binding(value=\"a\") Event event; " + + " @Inject @Binding(value=\"b\") Event> event1; " + + " @Inject @Binding(value=\"c\") Event> event2; " + + " @Inject @Binding(value=\"d\") Event> event3; " + + " @Inject @Binding(value=\"e\") Event> event4; " + + " @Inject @Binding(value=\"f\") Event event5; " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; "+ + "public class Generic { " + + " public void eventObserver( @Observes @Binding(value=\"a\") T t){} "+ + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; "+ + "import java.util.List; " + + "import java.util.Collection; " + + "import java.util.Set; " + +"public class TestClass { " + + " public void eventObserver( @Observes @Binding(value=\"b\") List list){} "+ + " public void eventObserver1( @Observes @Binding(value=\"c\") List list){} "+ + " public void eventObserver2( @Observes @Binding(value=\"d\") Collection list){} "+ + " public void eventObserver3( @Observes @Binding(value=\"e\") Collection list){} "+ + " public void eventObserver4( @Observes @Binding(value=\"f\") T t){} "+ + "} "); + + inform("start raw and parameterized assignability event test"); + + MetadataModel metaModel = createBeansModel(); + metaModel.runReadAction(new MetadataModelAction() { + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType("foo.TestClass"); + Element clazz = ((DeclaredType) mirror).asElement(); + List children = clazz.getEnclosedElements(); + List methods = ElementFilter.methodsIn( children ); + + assertEquals(5, methods.size()); + Map observer2Field = new HashMap(); + for ( int i=0 ; i<5; i++){ + int eventIndex = i+1; + String observer = null; + if ( i==0 ){ + observer = "eventObserver"; + } + else { + observer = "eventObserver"+i; + } + observer2Field.put(observer, "event"+eventIndex); + } + + for (ExecutableElement method : methods) { + Name simpleName = method.getSimpleName(); + List eventInjectionPoints = + model.getEventInjectionPoints( method , (DeclaredType) mirror); + assertEquals( "Found "+eventInjectionPoints.size()+" event " + + "injections for '"+simpleName+"' method", 1, + eventInjectionPoints.size()); + VariableElement variableElement = eventInjectionPoints.get(0); + TypeElement enclosingType = model.getCompilationController().getElementUtilities(). + enclosingTypeElement( variableElement); + assertEquals("Unexpected enclosing type for event injection :"+ + variableElement.getSimpleName(), "foo.Clazz", + enclosingType.getQualifiedName().toString()); + String varName = variableElement.getSimpleName().toString(); + assertEquals( "Observer '"+simpleName+"' has wrong event injectable", + observer2Field.get( simpleName.toString()), varName ); + } + + + mirror = model.resolveType("foo.Generic"); + clazz = ((DeclaredType) mirror).asElement(); + children = clazz.getEnclosedElements(); + methods = ElementFilter.methodsIn( children ); + assertEquals(1, methods.size()); + ExecutableElement method = (ExecutableElement)methods.get(0 ); + + List eventInjectionPoints = + model.getEventInjectionPoints(method, (DeclaredType) mirror); + assertEquals("Expected only one event injection for observer method " + + "'foo.Generic.eventObserver'", 1, eventInjectionPoints.size()); + VariableElement variableElement = eventInjectionPoints.get(0); + TypeElement enclosingType = model.getCompilationController().getElementUtilities(). + enclosingTypeElement( variableElement); + assertEquals("Unexpected enclosing type for event injection :"+ + variableElement.getSimpleName(), "foo.Clazz", + enclosingType.getQualifiedName().toString()); + String varName = variableElement.getSimpleName().toString(); + assertEquals( "Observer 'foo.Generic.eventObserver' has wrong event injectable", + "event", varName ); + + return null; + } + + }); + } + + private void anyEventsCheck( WebBeansModel model ) { + TypeMirror mirror = model.resolveType("foo.TestClass1"); + Element clazz = ((DeclaredType) mirror).asElement(); + List children = clazz.getEnclosedElements(); + List methods = ElementFilter.methodsIn( children ); + assertEquals(4, methods.size()); + for (ExecutableElement method : methods) { + Name simpleName = method.getSimpleName(); + List eventInjectionPoints = + model.getEventInjectionPoints( method , (DeclaredType) mirror); + Set fields = new HashSet(); + for (VariableElement variableElement : eventInjectionPoints) { + String name = variableElement.getSimpleName().toString(); + fields.add( name ); + TypeElement containingClass = model.getCompilationController().getElementUtilities(). + enclosingTypeElement( variableElement); + assertEquals("Event injection points are expected to be in 'foo.Clazz';" + + "but found injection point '"+name +"' in the class '" + +containingClass.getQualifiedName(), "foo.Clazz", + containingClass.getQualifiedName().toString()); + } + + if ( "eventObserver".contentEquals(simpleName)|| + "eventObserver1".contentEquals(simpleName)) + { + assertEquals("Expected exactly 2 event injections for observer "+ + simpleName+" but found :" +fields.size(), 2, fields.size()); + assertTrue( "Expected 'event' field as injection point", fields.contains("event")); + assertTrue( "Expected 'event1' field as injection point", fields.contains("event1")); + } + else if ( "eventObserver2".contentEquals(simpleName) || + "eventObserver3".contentEquals(simpleName)) + { + assertEquals("Expected exactly 3 event injections for observer "+ + simpleName+" but found :" +fields.size(), 3, fields.size()); + assertTrue( "Expected 'event' field as injection point", fields.contains("event")); + assertTrue( "Expected 'event1' field as injection point", fields.contains("event1")); + assertTrue( "Expected 'event2' field as injection point", fields.contains("event2")); + } + } + } + + private void unmatchedObserversCheck( WebBeansModel model , int size ) { + TypeMirror mirror = model.resolveType("foo.TestClass2"); + Element clazz = ((DeclaredType) mirror).asElement(); + List children = clazz.getEnclosedElements(); + List methods = ElementFilter.methodsIn( children ); + assertEquals(size, methods.size()); + for (ExecutableElement method : methods) { + List eventInjectionPoints = model. + getEventInjectionPoints(method, (DeclaredType) mirror); + if ( eventInjectionPoints.size() >0 ){ + VariableElement variableElement = eventInjectionPoints.get(0); + TypeElement containingType = model.getCompilationController().getElementUtilities(). + enclosingTypeElement(variableElement); + assertTrue( "Found unexpected observer 'foo.TestClass2."+ + method.getSimpleName()+"' for event injection" + + " point :'"+containingType.getQualifiedName() + +"."+variableElement.getSimpleName()+"'", false ); + } + } + } + + private void bindingMembersCheck( WebBeansModel model ) { + TypeMirror mirror = model.resolveType("foo.TestClass1"); + Element clazz = ((DeclaredType) mirror).asElement(); + List children = clazz.getEnclosedElements(); + List methods = ElementFilter.methodsIn( children ); + assertEquals(2, methods.size()); + for (ExecutableElement method : methods) { + Name simpleName = method.getSimpleName(); + List eventInjectionPoints = model. + getEventInjectionPoints( method, (DeclaredType) mirror); + assertEquals("Observer "+simpleName+" matches "+eventInjectionPoints.size() + +" events. But should match exactly one", 1, eventInjectionPoints.size()); + VariableElement variableElement = eventInjectionPoints.get(0); + TypeElement containingType = model.getCompilationController(). + getElementUtilities().enclosingTypeElement( variableElement); + Name varName = variableElement.getSimpleName(); + assertEquals("Event injection point should be inside class foo.Clazz," + + "but found inside "+ containingType.getQualifiedName(), + "foo.Clazz", containingType.getQualifiedName().toString()); + assertEquals("Observer method "+simpleName+" should match to" + + " event field 'event', but found :"+varName, "event", varName.toString()); + } + + } + + private void commonCheck( WebBeansModel model , String className, boolean + twoObservers) + { + TypeMirror mirror = model.resolveType(className); + Element clazz = ((DeclaredType) mirror).asElement(); + List children = clazz.getEnclosedElements(); + List methods = ElementFilter.methodsIn( children ); + + assertEquals( 2, methods.size()); + ExecutableElement observer= null; + List observerMethods = getObserverMethods(model , methods); + if ( twoObservers ){ + assertEquals( 2, observerMethods.size()); + ExecutableElement method1 = observerMethods.get( 0 ); + ExecutableElement method2 = observerMethods.get( 1 ); + ExecutableElement nonMatchedObserver = null; + if ( method1.getSimpleName().contentEquals("eventObserver")){ + observer = method1; + nonMatchedObserver = method2; + } + else { + observer =method2; + nonMatchedObserver = method1; + } + checkInjectionEvent(model, mirror, observer); + List eventInjectionPoints = model.getEventInjectionPoints( + nonMatchedObserver, (DeclaredType) mirror); + if ( eventInjectionPoints.size() >0 ){ + assertTrue( "Found unexpected observer '"+className+"."+ + nonMatchedObserver.getSimpleName()+" for event :"+ + eventInjectionPoints.get(0).getSimpleName() , false); + } + } + else { + assertEquals( 1, observerMethods.size()); + observer = observerMethods.get(0); + assertEquals("eventObserver", observer.getSimpleName().toString()); + checkInjectionEvent(model, mirror, observer); + } + } + + private void checkInjectionEvent( WebBeansModel model, TypeMirror mirror, + ExecutableElement observer ) + { + List injections = model.getEventInjectionPoints( observer, + (DeclaredType) mirror); + assertEquals( + "Should be exactly one event injection , but found " + + injections.size() + " events", + 1, injections.size()); + VariableElement variableElement = injections.get( 0 ); + assertNotNull( variableElement ); + assertEquals("event", variableElement.getSimpleName().toString()); + TypeElement type = model.getCompilationController().getElementUtilities(). + enclosingTypeElement( variableElement); + assertNotNull( type ); + assertEquals("foo.Clazz", type.getQualifiedName().toString()); + } + + private List getObserverMethods(WebBeansModel model, + List methods){ + List result = new ArrayList( methods.size()); + for (ExecutableElement method : methods) { + if ( model.getObserverParameter( method ) != null ){ + result.add( method ); + } + } + return result; + } +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/InterceptorBindingsTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/InterceptorBindingsTest.java new file mode 100644 index 000000000000..7796672fc5d2 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/InterceptorBindingsTest.java @@ -0,0 +1,354 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class InterceptorBindingsTest extends CommonTestCase { + + public InterceptorBindingsTest( String testName ) { + super(testName); + } + + public void testClassInterceptorBindings() throws IOException{ + + createInterceptorBinding("IBinding1"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/IBinding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.web.beansenterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.interceptor.*; "+ + "@InterceptorBinding " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, TYPE}) "+ + "@IBinding1 "+ + "public @interface IBinding2 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/IBinding3.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.interceptor.*; "+ + "@InterceptorBinding " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, TYPE}) "+ + "@IBinding1 "+ + "@Inherited "+ + "public @interface IBinding3 {} "); + + createInterceptorBinding("IBinding4"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + "@Inherited "+ + "public @interface Stereotype1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + "@IBinding4 "+ + "public @interface Stereotype2 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype3.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + "@Stereotype2 "+ + "public @interface Stereotype3 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/IBinding5.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.interceptor.*; "+ + "@InterceptorBinding " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, TYPE}) "+ + "@Stereotype2 "+ + "public @interface IBinding5 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@IBinding3 @Stereotype1 "+ + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "@IBinding2 @Stereotype2 "+ + "public class Two extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "@Stereotype3 "+ + "public class Three extends Two {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Four.java", + "package foo; " + + "@IBinding4 "+ + "public class Four extends Three {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Five.java", + "package foo; " + + "@IBinding5 "+ + "public class Five {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Six.java", + "package foo; " + + "@Stereotype3 "+ + "public class Six {}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + checkInterceptorBindings(model, "foo.One" , "foo.IBinding3", + "foo.IBinding1"); + + checkInterceptorBindings(model, "foo.Two" , "foo.IBinding2", + "foo.IBinding4", "foo.IBinding3", "foo.IBinding1"); + + checkInterceptorBindings(model, "foo.Three" , "foo.IBinding4", + "foo.IBinding3", "foo.IBinding1"); + + checkInterceptorBindings(model, "foo.Four" , "foo.IBinding4", + "foo.IBinding3", "foo.IBinding1"); + + checkInterceptorBindings(model, "foo.Five" , "foo.IBinding5"); + + checkInterceptorBindings(model, "foo.Six" , "foo.IBinding4"); + + return null; + } + + }); + } + + public void testMethodInterceptorBindings() throws IOException{ + + createInterceptorBinding("IBinding1"); + createInterceptorBinding("IBinding2"); + createInterceptorBinding("IBinding3"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + "@IBinding2 "+ + "public @interface Stereotype1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + "@Stereotype1 "+ + "public @interface Stereotype2 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@IBinding1 "+ + "public class One {" + + " void @IBinding3 method1(){} "+ + " void @Stereotype2 method2(){} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "@Stereotype2 "+ + "public class Two {" + + " void @IBinding1 method(){} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "public class Three {" + + " void @IBinding1 method(){} "+ + "}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + checkMethodInterceptorBindings(model, "foo.One", "method1", + "foo.IBinding1","foo.IBinding3"); + + checkMethodInterceptorBindings(model, "foo.One", "method2", + "foo.IBinding1","foo.IBinding2"); + + checkMethodInterceptorBindings(model, "foo.Two", "method", + "foo.IBinding1","foo.IBinding2"); + + checkMethodInterceptorBindings(model, "foo.Three", "method", + "foo.IBinding1"); + return null; + } + + }); + } + + private void checkMethodInterceptorBindings( WebBeansModel model , + String typeElement, String methodName, String... annotationFqns) + { + TypeMirror mirror = model.resolveType( typeElement ); + Element clazz = ((DeclaredType)mirror).asElement(); + List methods = ElementFilter.methodsIn( + clazz.getEnclosedElements()); + ExecutableElement element = null; + for (ExecutableElement method : methods) { + String name = method.getSimpleName().toString(); + if ( name.equals( methodName)){ + element = method; + break; + } + } + + assertNotNull( element ); + checkInterceptorBindings(model, element, annotationFqns); + } + + private void checkInterceptorBindings( WebBeansModel model, Element element, + String... annotationFqns ) + { + Collection interceptorBindings = + model.getInterceptorBindings(element); + + Set fqns = getIBindingFqns(interceptorBindings); + + Set expected = new HashSet( Arrays.asList( annotationFqns)); + expected.removeAll( fqns ); + if ( expected.size() >0 ){ + StringBuilder builder = new StringBuilder(); + for (String fqn : expected) { + builder.append(fqn); + builder.append(", "); + } + assertFalse( "Elements "+builder+" are not found ", true); + } + + List expectedList = Arrays.asList( annotationFqns); + fqns.removeAll( expectedList ); + if ( fqns.size() >0 ){ + StringBuilder builder = new StringBuilder(); + for (String fqn : fqns) { + builder.append(fqn); + builder.append(", "); + } + assertFalse( "Interceptor bindings "+builder+" are found but not expected", true); + } + } + + private void checkInterceptorBindings( WebBeansModel model , + String typeElement, String... annotationFqns) + { + TypeMirror mirror = model.resolveType( typeElement ); + Element clazz = ((DeclaredType)mirror).asElement(); + + checkInterceptorBindings(model, clazz, annotationFqns); + } + + private Set getIBindingFqns( + Collection interceptorBindings ) + { + Set fqns = new HashSet(); + for (AnnotationMirror annotationMirror : interceptorBindings) { + Element iBinding = annotationMirror.getAnnotationType().asElement(); + if ( iBinding instanceof TypeElement ){ + fqns.add( ((TypeElement)iBinding).getQualifiedName().toString()); + } + } + return fqns; + } +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/InterceptorResolutionTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/InterceptorResolutionTest.java new file mode 100644 index 000000000000..13325671a45f --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/InterceptorResolutionTest.java @@ -0,0 +1,612 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.InterceptorsResult; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class InterceptorResolutionTest extends CommonTestCase { + + public InterceptorResolutionTest( String testName ) { + super(testName); + } + + public void testSimpleInterceptorCase() throws IOException{ + createInterceptorBinding("IBinding1"); + createInterceptorBinding("IBinding2"); + createInterceptorBinding("IBinding3"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@IBinding1 "+ + "public class One {" + + " void method1(){} "+ + " @IBinding2 @IBinding3 void method2(){} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iceptor1.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "@Interceptor "+ + "@IBinding1 "+ + "public class Iceptor1 {" + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iceptor2.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "@Interceptor "+ + "@IBinding3 "+ + "public class Iceptor2 {" + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iceptor3.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "@Interceptor "+ + "@IBinding2 @IBinding1 "+ + "public class Iceptor3 {" + + "}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + checkInterceptors(model, "foo.One", "foo.Iceptor1"); + + checkMethodInterceptors(model, "foo.One", "method1", "foo.Iceptor1"); + + checkMethodInterceptors(model, "foo.One", "method2", "foo.Iceptor1", + "foo.Iceptor2", "foo.Iceptor3"); + + return null; + } + + }); + } + + public void testInterceptorNonbindingMembers() throws IOException{ + TestUtilities.copyStringToFileObject(srcFO, "foo/IBinding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.interceptor.*; "+ + "import jakarta.enterprise.util.*; "+ + "@InterceptorBinding " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, TYPE}) "+ + "public @interface IBinding1 {" + + " String value() ;"+ + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/IBinding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.interceptor.*; "+ + "import jakarta.enterprise.util.*; "+ + "@InterceptorBinding " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, TYPE}) "+ + "public @interface IBinding2 {" + + " String value() ;"+ + " @Nonbinding String comment() defualt \"\" ; "+ + "} "); + createInterceptorBinding("IBinding3"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@IBinding1(\"d\") "+ + "public class One {" + + " void method1(){} "+ + " @IBinding2(\"a\") @IBinding3 void method2(){} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iceptor1.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "@Interceptor "+ + "@IBinding1(\"e\") "+ + "public class Iceptor1 {" + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iceptor2.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "@Interceptor "+ + "@IBinding3 @IBinding2(value=\"a\",comment=\"c\")"+ + "public class Iceptor2 {" + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iceptor3.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "@Interceptor "+ + "@IBinding2(\"b\") @IBinding1 "+ + "public class Iceptor3 {" + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iceptor4.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "@Interceptor "+ + "@IBinding1(\"d\") "+ + "public class Iceptor4 {" + + "}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + checkInterceptors(model, "foo.One", "foo.Iceptor4"); + + checkMethodInterceptors(model, "foo.One", "method1", "foo.Iceptor4"); + + checkMethodInterceptors(model, "foo.One", "method2", "foo.Iceptor2", + "foo.Iceptor4"); + + return null; + } + + }); + } + + public void testEnabledInterceptor() throws IOException{ + createInterceptorBinding("IBinding1"); + createInterceptorBinding("IBinding2"); + + TestUtilities.copyStringToFileObject(srcFO, "beans.xml", + " " + + "" + + " "+ + "foo.Iceptor2"+ + "foo.Iceptor3"+ + " " + + ""); + + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@IBinding1 "+ + "public class One {" + + " void @IBinding2 method1(){} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iceptor1.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "@Interceptor "+ + "@IBinding1 "+ + "public class Iceptor1 {" + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iceptor2.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "@Interceptor "+ + "@IBinding2 "+ + "public class Iceptor2 {" + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iceptor3.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "@Interceptor "+ + "@IBinding2 @IBinding1 "+ + "public class Iceptor3 {" + + "}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + checkMethodEnabledInterceptors(model, "foo.One", "method1", + new String[]{ "foo.Iceptor2" , "foo.Iceptor3"}, "foo.Iceptor1"); + + return null; + } + + }); + } + + public void testDeclaredInterceptor() throws IOException{ + createInterceptorBinding("IBinding1"); + + TestUtilities.copyStringToFileObject(srcFO, "beans.xml", + " " + + "" + + " "+ + " " + + ""); + + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "@Interceptors({DeclaredIceptor1.class, DeclaredIceptor2.class}) "+ + "public class One {" + + " void @IBinding1 @Interceptors({DeclaredIceptor3.class}) method(){} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iceptor1.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "@Interceptor "+ + "@IBinding1 "+ + "public class Iceptor1 {" + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/DeclaredIceptor1.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "public class DeclaredIceptor1 {" + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/DeclaredIceptor2.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "public class DeclaredIceptor2 {" + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/DeclaredIceptor3.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "public class DeclaredIceptor3 {" + + "}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + checkInterceptors(model, "foo.One", false, "foo.DeclaredIceptor1", + "foo.DeclaredIceptor2" ); + + checkMethodInterceptors(model, "foo.One", "method", false , + "foo.DeclaredIceptor1", "foo.DeclaredIceptor2", + "foo.DeclaredIceptor3"); + + return null; + } + + }); + } + + public void testInterceptorMixedCases() throws IOException{ + TestUtilities.copyStringToFileObject(srcFO, "foo/IBinding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.interceptor.*; "+ + "import jakarta.enterprise.util.*; "+ + "@InterceptorBinding " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, TYPE}) "+ + "public @interface IBinding1 {" + + " String value() ;"+ + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/IBinding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.interceptor.*; "+ + "import jakarta.enterprise.util.*; "+ + "@InterceptorBinding " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, TYPE}) "+ + "@IBinding1(\"a\") "+ + "public @interface IBinding2 {" + + "} "); + createInterceptorBinding("IBinding3"); + createInterceptorBinding("IBinding4"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@IBinding4 "+ + "@Stereotype "+ + "public @interface Stereotype1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + "@Stereotype1 "+ + "public @interface Stereotype2 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@IBinding3 "+ + "public class One {" + + " void @IBinding2 method1(){} "+ + " @Stereotype2 @IBinding1(\"c\") void method2(){} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "@Stereotype1 "+ + "public class Two {" + + " void @IBinding1(\"b\") method(){} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iceptor1.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "@Interceptor "+ + "@IBinding1(\"a\") "+ + "public class Iceptor1 {" + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iceptor2.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "@Interceptor "+ + "@IBinding3 @IBinding4 @IBinding1(\"d\")"+ + "public class Iceptor2 {" + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iceptor3.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "@Interceptor "+ + "@IBinding4 @IBinding1(\"b\") "+ + "public class Iceptor3 {" + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iceptor4.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "@Interceptor "+ + "@Stereotype2 @IBinding1(\"b\") "+ + "public class Iceptor4 {" + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iceptor5.java", + "package foo; " + + "import jakarta.interceptor.*; "+ + "@Interceptor "+ + "@Stereotype1 @IBinding1(\"c\") "+ + "public class Iceptor5 {" + + "}" ); + + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + checkInterceptors(model, "foo.One" ); + + checkMethodInterceptors(model, "foo.One", "method1", "foo.Iceptor1"); + + checkMethodInterceptors(model, "foo.One", "method2", "foo.Iceptor5"); + + checkMethodInterceptors(model, "foo.Two", "method", "foo.Iceptor3", + "foo.Iceptor4" ); + + return null; + } + + }); + } + + private void checkInterceptors(WebBeansModel model , String className , + String... interceptorFqns) + { + checkInterceptors(model, className, true , interceptorFqns); + } + + private void checkInterceptors(WebBeansModel model , String className , + boolean resolved, String... interceptorFqns) + { + TypeMirror type = model.resolveType( className ); + Element clazz = model.getCompilationController().getTypes().asElement( type ); + + checkInterceptors(model, clazz, resolved , interceptorFqns); + } + + private InterceptorsResult checkMethodInterceptors(WebBeansModel model , + String className , String methodName, String... interceptorFqns) + { + return checkMethodInterceptors(model, className, methodName, + true, interceptorFqns); + } + + private InterceptorsResult checkMethodInterceptors(WebBeansModel model , + String className , String methodName, boolean resolved , + String... interceptorFqns) + { + ExecutableElement element = getMethod(model, className, methodName); + + assertNotNull( element ); + return checkInterceptors(model, element, resolved, interceptorFqns); + } + + private ExecutableElement getMethod( WebBeansModel model, String className, + String methodName ) + { + TypeMirror type = model.resolveType( className ); + Element clazz = model.getCompilationController().getTypes().asElement( type ); + + List methods = ElementFilter.methodsIn( + clazz.getEnclosedElements() ); + ExecutableElement element = null; + for (ExecutableElement executableElement : methods) { + String name = executableElement.getSimpleName().toString(); + if ( name.equals(methodName )){ + element = executableElement; + break; + } + } + return element; + } + + private void checkMethodEnabledInterceptors(WebBeansModel model , + String className , String methodName, String[] enabledInterceptors, + String... disabledInterceptors ) + { + List list = new LinkedList( Arrays.asList( enabledInterceptors )); + list.addAll( Arrays.asList( disabledInterceptors )); + InterceptorsResult result = checkMethodInterceptors(model, className, + methodName, list.toArray( new String[0] )); + + Set disabled = new HashSet(); + Set enabled = new HashSet(); + List allInterceptors = result.getAllInterceptors(); + for (TypeElement typeElement : allInterceptors) { + if ( result.isDisabled(typeElement)){ + disabled.add( typeElement.getQualifiedName().toString()); + } + else { + enabled.add( typeElement.getQualifiedName().toString()); + } + } + + Set requiredEnabled = new HashSet( Arrays.asList( enabledInterceptors)); + compareCollections(enabled, requiredEnabled, "Not found enabled interceptors :"); + compareCollections(Arrays.asList( enabledInterceptors), + enabled, "These interceptos are unexpectedly enabled :"); + + Set requiredDisabled = new HashSet( Arrays.asList( disabledInterceptors)); + compareCollections(disabled, requiredDisabled, "Not found disabled interceptors :"); + compareCollections(Arrays.asList( disabledInterceptors), + disabled, "These interceptos are unexpectedly disabled :"); + } + + private void compareCollections( Collection actual,Set required , + String errorMessage ) + { + required.removeAll( actual ); + if ( !required.isEmpty()){ + StringBuilder builder = new StringBuilder(); + for (String fqn : required) { + builder.append( fqn ); + builder.append(" , "); + } + assertFalse( errorMessage+ builder.toString() ,true ); + } + } + + private InterceptorsResult checkInterceptors( WebBeansModel model, Element element, + String... interceptorFqns ) + { + return checkInterceptors(model, element, true , interceptorFqns); + } + + private InterceptorsResult checkInterceptors( WebBeansModel model, Element element, + boolean resolved , String... interceptorFqns ) + { + InterceptorsResult result = model.getInterceptors(element); + Collection interceptors = null; + if ( resolved ){ + interceptors = result.getResolvedInterceptors(); + } + else { + interceptors = result.getDeclaredInterceptors(); + } + Set foundIceptors = new HashSet(); + for (TypeElement typeElement : interceptors) { + String fqn = typeElement.getQualifiedName().toString(); + foundIceptors.add( fqn ); + } + Set requiredFqns = new HashSet( Arrays.asList( interceptorFqns)); + + requiredFqns.removeAll( foundIceptors ); + if ( !requiredFqns.isEmpty() ){ + StringBuilder builder = new StringBuilder(); + for( String fqn : requiredFqns ){ + builder.append( fqn ); + builder.append(", "); + } + assertFalse("Interceptors "+builder+" are exepcted but not found", true ); + } + + foundIceptors.removeAll(Arrays.asList( interceptorFqns)); + if ( !foundIceptors.isEmpty() ){ + StringBuilder builder = new StringBuilder(); + for( String fqn : foundIceptors ){ + builder.append( fqn ); + builder.append(", "); + } + assertFalse("Interceptors "+builder+" found but not expected", true ); + } + return result; + } +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/ModelTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/ModelTest.java new file mode 100644 index 000000000000..18495a4f90b7 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/ModelTest.java @@ -0,0 +1,574 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelException; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class ModelTest extends CommonTestCase { + + public ModelTest( String testName ) { + super(testName); + } + + public void testInjectionPointInitialization() throws MetadataModelException, + IOException, InterruptedException + { + createQualifier("CustomBinding"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class CustomClass {" + + " @Inject @foo.CustomBinding Object myFieldA = new Object(); "+ + " @Inject @foo.CustomBinding Object myFieldB ; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@foo.CustomBinding " + + "public class One {}" ); + + + TestWebBeansModelImpl modelImpl = createModelImpl(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.CustomClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List fields = ElementFilter.fieldsIn( + clazz.getEnclosedElements()); + Map variables = + new HashMap(); + for (VariableElement field : fields) { + variables.put(field.getSimpleName().toString(), field); + } + VariableElement fieldA = variables.get("myFieldA"); + assertNotNull( fieldA ); + DependencyInjectionResult result = model.lookupInjectables(fieldA, + null, new AtomicBoolean(false)); + assertEquals(DependencyInjectionResult.ResultKind.DEFINITION_ERROR, + result.getKind()); + assertTrue( result instanceof DependencyInjectionResult.Error); + + VariableElement fieldB = variables.get("myFieldB"); + assertNotNull( fieldB ); + result = model.lookupInjectables(fieldB, null, new AtomicBoolean(false)); + assertEquals(DependencyInjectionResult.ResultKind.INJECTABLE_RESOLVED, + result.getKind()); + return null; + } + + }); + } + + public void testCommon() throws MetadataModelException, IOException, + InterruptedException + { + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomBinding.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.enterprise.util.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.enterprise.util.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "@Inherited "+ + "public @interface CustomBinding {" + + " String value(); "+ + " @Nonbinding String comment() default \"\"; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class CustomClass {" + + " @Inject @foo.CustomBinding(value=\"a\") Object myFieldA; "+ + " String myText[]; "+ + " @Inject @foo.CustomBinding(value=\"d\", comment=\"c\") int myIndex; "+ + " Class myClass; "+ + " @Inject @foo.CustomBinding(value=\"b\", comment=\"comment\")" + + " foo.Generic myThread; "+ + " @Inject @foo.CustomBinding(value=\"c\")" + + " foo.Generic myGen; "+ + " @Inject @foo.CustomBinding(value=\"e\") Thread myFieldB; "+ + " void method( Object param ){}"+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@foo.CustomBinding(value=\"a\") " + + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "public class Two extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "@foo.CustomBinding() " + + "public class Three { " + + " @Produces @foo.CustomBinding(value=\"d\") " + + "int productionField =1; " + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@foo.CustomBinding(\"c\") "+ + "public class Generic {" + + " @Produces @foo.CustomBinding(value=\"e\") foo.MyThread getThread(){" + + " return null; } "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@foo.CustomBinding(\"b\") "+ + "public class Generic1 extends Generic{}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/MyThread.java", + "package foo; " + + "public class MyThread extends Thread {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/MyClass.java", + "package foo; " + + "public class MyClass extends Class {}" ); + + inform("start common test"); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.CustomClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + else if ( element instanceof ExecutableElement ){ + List params = + ((ExecutableElement)element).getParameters(); + for (VariableElement variableElement : params) { + injectionPoints.add( variableElement ); + } + } + } + + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myFieldA")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.One", "foo.Two"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + else if ( element.getSimpleName().contentEquals("myGen")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.Generic"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + else if ( element.getSimpleName().contentEquals("myIndex")){ + assertFindVariableResultInjectables((VariableElement)element, provider); + assertFindVariableResultProductionsVar((VariableElement)element, provider, "productionField"); + } + else if ( element.getSimpleName().contentEquals("myFieldB")){ + assertFindVariableResultInjectables((VariableElement)element, provider); + assertFindVariableResultProductions((VariableElement)element, provider, "getThread"); + } + else if ( element.getSimpleName().contentEquals("myThread")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.Generic1"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + } + + assert names.contains("myFieldA"); + assert names.contains("myGen"); + assert names.contains("myIndex"); + assert names.contains("myFieldB"); + assert names.contains("myThread"); + + return null; + } + + }); + } + + public void testInjectable() throws MetadataModelException, IOException, + InterruptedException + { + + TestUtilities.copyStringToFileObject(srcFO, "foo/Fast.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Fast {" + + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Slow.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Slow {" + + "}"); + TestUtilities.copyStringToFileObject(srcFO, "foo/Producer.java", + "package foo; " + + "import java.util.List; " + + "public interface Producer { " + + " List getItems(); " + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SlowProducer.java", + "package foo; " + + "import java.util.List; " + + "import jakarta.enterprise.inject.Default; " + + "@Slow @Default " + + "public class SlowProducer implements Producer { " + + " public List getItems() { return null;} " + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/FastProducer.java", + "package foo; " + + "import java.util.List; " + + "import jakarta.enterprise.inject.Default; " + + "@Fast @Default " + + "public class FastProducer implements Producer { " + + " public List getItems() { return null;} " + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/User.java", + "package foo; " + + "import java.util.List; " + + "import jakarta.inject.*; "+ + "import jakarta.enterprise.inject.Default; " + + "public class User { " + + " @Inject @Slow @Default " + + " public Producer mySlowProducer; " + + " @Inject @Fast @Default " + + " public Producer myFastProducer; " + + " @Inject @Default " + + " public Producer myAmbiguousProducer; " + + "}" ); + + inform("start injectable test"); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.User" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("mySlowProducer")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.SlowProducer"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + else if ( element.getSimpleName().contentEquals("mySlowProducer")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.FastProducer"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + else if ( element.getSimpleName().contentEquals("myAmbiguousProducer")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.SlowProducer", "foo.FastProducer", "foo.Producer"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + } + + assert names.contains("mySlowProducer"); + assert names.contains("myFastProducer"); + assert names.contains("myAmbiguousProducer"); + + return null; + } + + }); + } + + + + public void testMixedBindings() throws MetadataModelException, IOException, + InterruptedException + { + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.enterprise.util.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "import jakarta.enterprise.util.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {" + + " String value(); "+ + " @Nonbinding String comment() default \"\"; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding2 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding3.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding3 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding4.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding4 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface1.java", + "package foo; " + + "public interface Iface1 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface2.java", + "package foo; " + + "public interface Iface2 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface3.java", + "package foo; " + + "public interface Iface3 extends Iface1 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class Clazz1 {" + + " @Produces @foo.Binding1(\"b\") int productionField1 = 1; " + + " @Produces @foo.Binding3 @foo.Binding2 String[] productionField2 = new String[0]; " + + " @Produces @foo.Binding1(\"c\") @foo.Binding4 Clazz3 productionMethod() " + + "{ return null; } " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz2.java", + "package foo; " + + "@foo.Binding1(\"a\") "+ + "public class Clazz2 extends Clazz1 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz3.java", + "package foo; " + + "@foo.Binding3 @foo.Binding2 "+ + "public class Clazz3 extends Clazz2 implements Iface1 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz4.java", + "package foo; " + + "@foo.Binding3 @foo.Binding1(\"a\") "+ + "public class Clazz4 implements Iface2, Iface3 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz5.java", + "package foo; " + + "@foo.Binding3 @foo.Binding1(\"b\") "+ + "public class Clazz5 implements Iface3 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz6.java", + "package foo; " + + "@foo.Binding1(\"a\") @foo.Binding2 @foo.Binding4 "+ + "public class Clazz6 extends Clazz2 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.inject.*; "+ + "public class TestClass { " + + " @Inject @foo.Binding3 @foo.Binding1(\"a\") Iface1 myFieldA; "+ + " @Inject @foo.Binding2 Iface1 myFieldB; "+ + " @Inject @foo.Binding3 Clazz1 myFieldC; "+ + " @Inject @foo.Binding2 @foo.Binding4 Clazz2 myFieldD; "+ + " @Inject @foo.Binding1(\"b\") Integer myFieldE; "+ + " @Inject @foo.Binding3 @foo.Binding2 String[] myFieldF; "+ + " @Inject @foo.Binding1(\"c\") @foo.Binding4 Clazz1 myFieldG; "+ + "} "); + + inform("start mixed binding test"); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myFieldA")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.Clazz4"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + else if ( element.getSimpleName().contentEquals("myFieldB")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.Clazz3"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + else if ( element.getSimpleName().contentEquals("myFieldC")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.Clazz3"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + else if ( element.getSimpleName().contentEquals("myFieldD")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.Clazz6"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + else if ( element.getSimpleName().contentEquals("myFieldE")){ + assertFindVariableResultInjectables((VariableElement)element, provider); + assertFindVariableResultProductionsVar((VariableElement)element, provider, "productionField1"); + } + else if ( element.getSimpleName().contentEquals("myFieldF")){ + assertFindVariableResultInjectables((VariableElement)element, provider); + assertFindVariableResultProductionsVar((VariableElement)element, provider, "productionField2"); + } + else if ( element.getSimpleName().contentEquals("myFieldG")){ + assertFindVariableResultInjectables((VariableElement)element, provider); + assertFindVariableResultProductions((VariableElement)element, provider, "productionMethod"); + } + } + + assert names.contains("myFieldA"); + assert names.contains("myFieldB"); + assert names.contains("myFieldC"); + assert names.contains("myFieldD"); + assert names.contains("myFieldE"); + assert names.contains("myFieldF"); + assert names.contains("myFieldG"); + return null; + } + }); + + } + +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/NamedTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/NamedTest.java new file mode 100644 index 000000000000..9f5b78f8c78c --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/NamedTest.java @@ -0,0 +1,393 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import static junit.framework.TestCase.assertEquals; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class NamedTest extends CommonTestCase { + + public NamedTest( String testName ) { + super(testName); + } + + public void testPlainNamed() throws IOException { + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import javainject.*; "+ + " @Named "+ + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.inject.*; "+ + " @Named(\"twoClass\") "+ + "public class Two extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface.java", + "package foo; " + + "import jakarta.inject.*; "+ + " @Named "+ + "public interface Iface {}" ); + + + TestUtilities.copyStringToFileObject(srcFO, "foo/CApital.java", + "package foo; " + + "import jakarta.inject.*; "+ + " @Named "+ + "public class CApital {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Tree.java", + "package foo; " + + "import jakarta.inject.*; "+ + "public class Tree {" + + " @Named int myField1; "+ + " @Named(\"field\") int myField2; "+ + " @Named void method(){} "+ + " @Named int getValue(){ return 0; } "+ + " @Named(\"stringGetter\") String getString(){ return null; } "+ + "}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + public Void run( WebBeansModel model ) throws Exception { + List namedElements = model.getNamedElements(); + Element one = null; + Element two = null; + Element iface = null; + Element field1 = null; + Element field2 = null; + Element method = null; + Element value = null; + Element getter = null; + for (Element element : namedElements) { + if ( element instanceof TypeElement ){ + String fqn = ((TypeElement)element).getQualifiedName().toString(); + if ( "foo.One".equals(fqn)){ + one = element; + String name = model.getName(element); + assertEquals("one", name); + } + else if ( "foo.Two".equals( fqn )){ + two = element; + String name = model.getName(element); + assertEquals("twoClass", name); + } + else if ( "foo.Iface".equals( fqn )){ + iface = element; + String name = model.getName(element); + assertEquals("iface", name); + } + // #249438 + else if ("foo.CApital".equals(fqn)) { + iface = element; + String name = model.getName(element); + assertEquals("CApital", name); + } + } + else if ( element instanceof VariableElement ){ + String name = element.getSimpleName().toString(); + if ( "myField1".equals( name )){ + field1 = element; + name = model.getName(element); + assertEquals("myField1", name); + } + else if ( "myField2".equals(name )){ + field2 = element; + name = model.getName(element); + assertEquals("field", name); + } + } + else if ( element instanceof ExecutableElement ){ + String name = element.getSimpleName().toString(); + if ( "method".equals( name )){ + method = element; + name = model.getName(element); + assertEquals("method", name); + } + else if ( "getValue".equals(name )){ + value = element; + name = model.getName(element); + assertEquals("value", name); + } + else if ( "getString".equals(name )){ + getter = element; + name = model.getName(element); + assertEquals("stringGetter", name); + } + } + } + + assertNotNull( one ); + assertNotNull( two ); + assertNotNull( iface ); + assertNotNull( field1 ); + assertNotNull( field2 ); + assertNotNull( method ); + assertNotNull( value ); + assertNotNull( getter ); + return null; + } + }); + + } + + public void testStereotypeNamed() throws IOException { + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + " @Stereotype1 "+ + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "@Stereotype2 "+ + "public class Three {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "public class Two {" + + " @Stereotype1 int myField1; "+ + " @Stereotype2 int myField2; "+ + " @Stereotype1 void method(){} "+ + " @Stereotype2 int getValue(){ return 0; } "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Named "+ + "@Stereotype "+ + "public @interface Stereotype1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "@Retention(RUNTIME) "+ + "@Stereotype "+ + "@Stereotype1 "+ + "public @interface Stereotype2 {}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + public Void run( WebBeansModel model ) throws Exception { + List namedElements = model.getNamedElements(); + Element one = null; + Element three = null; + Element field1 = null; + Element field2 = null; + Element method = null; + Element value = null; + for (Element element : namedElements) { + if ( element instanceof TypeElement ){ + String fqn = ((TypeElement)element).getQualifiedName().toString(); + if ( "foo.One".equals(fqn)){ + one = element; + String name = model.getName(element); + assertEquals("one", name); + } + else if ( "foo.Three".equals( fqn )){ + three = element; + String name = model.getName(element); + assertEquals("three", name); + } + } + else if ( element instanceof VariableElement ){ + String name = element.getSimpleName().toString(); + if ( "myField1".equals( name )){ + field1 = element; + name = model.getName(element); + assertEquals("myField1", name); + } + else if ( "myField2".equals(name )){ + field2 = element; + name = model.getName(element); + assertEquals("myField2", name); + } + } + else if ( element instanceof ExecutableElement ){ + String name = element.getSimpleName().toString(); + if ( "method".equals( name )){ + method = element; + name = model.getName(element); + assertEquals("method", name); + } + else if ( "getValue".equals(name )){ + value = element; + name = model.getName(element); + assertEquals("value", name); + } + } + } + + assertNotNull( one ); + assertNotNull( three ); + assertNotNull( field1 ); + assertNotNull( field2 ); + assertNotNull( method ); + assertNotNull( value ); + return null; + } + }); + + } + + public void testSpecializesNamed() throws IOException { + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + " @Named "+ + "public class One {" + + " @Produces @Named(\"method\") void operation(){} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + " @Specializes "+ + "public class Three extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + " @Named(\"explicit\") "+ + "public class One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + " @Specializes "+ + "public class Two1 extends One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class Two extends One {" + + " @Produces @Specializes void operation(){} "+ + "}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + public Void run( WebBeansModel model ) throws Exception { + List namedElements = model.getNamedElements(); + Element one = null; + Element two = null; + Element three = null; + Element one1 = null; + Element two1 = null; + Element operation1 = null; + Element operation2 = null; + for (Element element : namedElements) { + if ( element instanceof TypeElement ){ + String fqn = ((TypeElement)element).getQualifiedName().toString(); + if ( "foo.One".equals(fqn)){ + one = element; + String name = model.getName(element); + assertEquals("one", name); + } + if ( "foo.Two".equals(fqn)){ + two = element; + } + else if ( "foo.Three".equals( fqn )){ + three = element; + String name = model.getName(element); + assertEquals("three", name); + } + if ( "foo.One1".equals(fqn)){ + one1 = element; + String name = model.getName(element); + assertEquals("explicit", name); + } + if ( "foo.Two1".equals(fqn)){ + two1 = element; + String name = model.getName(element); + assertEquals("explicit", name); + } + } + else if ( element instanceof ExecutableElement ){ + String name = element.getSimpleName().toString(); + if ( "operation".equals( name )){ + Element enclosingElement = element.getEnclosingElement(); + if ( enclosingElement.getSimpleName(). + contentEquals("One")){ + operation1 = element; + name = model.getName(element); + assertEquals("method", name); + } + else if ( enclosingElement.getSimpleName(). + contentEquals("Two")){ + operation2 = element; + name = model.getName(element); + assertEquals("method", name); + } + } + } + } + + assertNotNull( one ); + assertNull( two ); + assertNotNull( three ); + assertNotNull( one1 ); + assertNotNull( two1 ); + assertNotNull( operation1 ); + assertNotNull( operation2 ); + return null; + } + }); + + } +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/NewTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/NewTest.java new file mode 100644 index 000000000000..9e6f92cb429c --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/NewTest.java @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.impl.model.results.ResultImpl; + + +/** + * @author ads + * + */ +public class NewTest extends CommonTestCase { + + public NewTest( String testName ) { + super(testName); + } + + public void testNew() throws IOException, InterruptedException{ + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperClass.java", + "package foo; " + + "public class SuperClass { " + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "public class One extends SuperClass {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class TestClass {" + + " @Inject @New One myField1; "+ + " @Inject @New(Two.class) SuperClass myField2; "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding1 "+ + "public class Two extends SuperClass {}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myField1")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.One"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.Two"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + } + assert names.contains("myField1"); + assert names.contains("myField2"); + return null; + } + }); + + } + +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/ObserversTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/ObserversTest.java new file mode 100644 index 000000000000..6604793638bc --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/ObserversTest.java @@ -0,0 +1,698 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelException; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + +/** + * @author ads + * + */ +public class ObserversTest extends CommonTestCase { + + public ObserversTest(String testName){ + super( testName); + } + + public void testSimple () throws MetadataModelException, IOException, + InterruptedException + { + createQualifier("Binding"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/EventObject.java", + "package foo; " + + "public class EventObject { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.inject.*; "+ + "import jakarta.enterprise.event.Event; "+ + "public class TestClass {" + + " @Inject @foo.Binding Event event; " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; "+ + "public class Clazz {" + + " public void eventObserver( @Observes @foo.Binding EventObject event ) {}" + + "} "); + + inform("start simple observer test"); + + MetadataModel metaModel = createBeansModel() ; + metaModel.runReadAction(new MetadataModelAction(){ + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( ( VariableElement) element); + } + } + + assertEquals( 1, injectionPoints.size()); + VariableElement var = injectionPoints.get(0); + assertEquals( var.getSimpleName().toString(), "event"); + List observers = model.getObservers( var, + (DeclaredType)mirror ); + assertEquals( "Should be exactly one observer method , but found " + + observers.size() +" methods", 1, observers.size()); + ExecutableElement executableElement = observers.get(0); + assertNotNull( executableElement ); + String name = executableElement.getSimpleName().toString(); + assertEquals( "eventObserver" , name ); + return null; + } + }); + } + + public void testCommon () throws MetadataModelException, IOException, + InterruptedException + { + createQualifier("Binding"); + createQualifier("Binding1"); + createQualifier("Binding2"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperObject.java", + "package foo; " + + "public class SuperObject { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface.java", + "package foo; " + + "public interface Iface { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/EventObject.java", + "package foo; " + + "public class EventObject extends SuperObject implements Iface { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.inject.*; " + + "import jakarta.enterprise.event.Event; " + + "public class TestClass {" + + " @Inject @foo.Binding @foo.Binding2 Event event; " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO,"foo/Clazz1.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; " + + "public class Clazz1 {" + + " public void eventObserver( @Observes @foo.Binding @foo.Binding2 SuperObject event ) {}" + + " public void method( @foo.Binding @foo.Binding2 EventObject event ) {}" + + "} "); + + TestUtilities.copyStringToFileObject(srcFO,"foo/Clazz2.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; " + + "public class Clazz2 {" + + " public void eventObserver( @Observes @foo.Binding @foo.Binding2 Iface event ) {}" + + " public void notEventObserver( @Observes @foo.Binding @foo.Binding1 EventObject event ) {}" + + "} "); + + inform("start common observer test"); + + MetadataModel metaModel = createBeansModel(); + metaModel.runReadAction(new MetadataModelAction() { + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType("foo.TestClass"); + Element clazz = ((DeclaredType) mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = new ArrayList( + children.size()); + for (Element element : children) { + if (element instanceof VariableElement) { + injectionPoints.add((VariableElement) element); + } + } + + assertEquals( 1, injectionPoints.size()); + VariableElement var = injectionPoints.get(0); + assertEquals("event", var.getSimpleName().toString() ); + List observers = model.getObservers(var, + (DeclaredType) mirror); + assertEquals( + "Should be exactly two observer methods , but found " + + observers.size() + " methods", + 2, observers.size()); + boolean foundSuper = false; + boolean foundIface = false; + for (ExecutableElement executableElement : observers) { + String name = executableElement.getSimpleName().toString(); + assertEquals( "Found unexpected event observer method :"+ + name ,name , "eventObserver"); + TypeElement typeElement = model.getCompilationController(). + getElementUtilities().enclosingTypeElement( executableElement ); + String fqnType = typeElement.getQualifiedName().toString(); + if ( "foo.Clazz1".equals(fqnType)){ + foundSuper = true; + } + else if( "foo.Clazz2".equals( fqnType)){ + foundIface = true; + } + } + assertTrue( "Observer method inside Clazz1 is not found", foundSuper ); + assertTrue( "Observer method inside Clazz2 is not found" , foundIface); + return null; + } + }); + } + + public void testMembersQualifier () throws MetadataModelException, IOException, + InterruptedException + { + createQualifier("Binding"); + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {" + + " String value(); "+ + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.enterprise.util.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.enterprise.util.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding2 {" + + " @Nonbinding String comment() default \"\"; "+ + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperObject1.java", + "package foo; " + + "public class SuperObject1 { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperObject2.java", + "package foo; " + + "public class SuperObject2 extends SuperObject1 { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface1.java", + "package foo; " + + "public interface Iface1 { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface2.java", + "package foo; " + + "public interface Iface2 extends Iface1 { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/EventObject.java", + "package foo; " + + "public class EventObject extends SuperObject2 implements Iface2 { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.inject.*; " + + "import jakarta.enterprise.event.Event; " + + "public class TestClass {" + + " @Inject @foo.Binding2(comment=\"c\") @foo.Binding1(value=\"a\") Event event; " + + " @Inject @foo.Binding @foo.Binding1(value=\"b\") Event event1; " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO,"foo/Clazz1.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; " + + "public class Clazz1 {" + + " public void eventObserver( @Observes @foo.Binding " + + "@foo.Binding1(value=\"a\") @foo.Binding2(comment=\"other\")" + + " SuperObject1 event ) {}" + + " public void eventObserver1( @Observes " + + "@foo.Binding2(comment=\"any\") @foo.Binding1(value=\"a\") Iface1 event ) {}" + + "} "); + + TestUtilities.copyStringToFileObject(srcFO,"foo/Clazz2.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; " + + "public class Clazz2 {" + + " public void notEventObserver( @Observes @foo.Binding " + + "@foo.Binding2(comment=\"\") @foo.Binding1(value=\"b\") Iface2 event ) {}" + + " public void notEventObserver2( @Observes @foo.Binding " + + "@foo.Binding1(value=\"a\") EventObject event ) {}" + + " public void notEventObserver3( @Observes @foo.Binding " + + "@foo.Binding1(value=\"b\") Iface1 event ) {}" + + "} "); + + inform("start observer test with binding members"); + + MetadataModel metaModel = createBeansModel(); + metaModel.runReadAction(new MetadataModelAction() { + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType("foo.TestClass"); + Element clazz = ((DeclaredType) mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = new ArrayList( + children.size()); + for (Element element : children) { + if (element instanceof VariableElement) { + injectionPoints.add((VariableElement) element); + } + } + + assertEquals( 2, injectionPoints.size()); + VariableElement var1 = injectionPoints.get(0); + VariableElement var2 = injectionPoints.get(1); + String varName =var1.getSimpleName().toString(); + VariableElement var = "event".equals(varName) ? var1:var2; + List observers = model.getObservers(var, + (DeclaredType) mirror); + assertEquals( + "Should be exactly two observer methods , but found " + + observers.size() + " methods", + 2, observers.size()); + boolean foundSuper = false; + boolean foundIface = false; + for (ExecutableElement executableElement : observers) { + TypeElement typeElement = model.getCompilationController(). + getElementUtilities().enclosingTypeElement( executableElement ); + String fqnType = typeElement.getQualifiedName().toString(); + assertEquals("Observer methods are defined only inside foo.Clazz1," + + "but found : "+fqnType,"foo.Clazz1",fqnType); + String name = executableElement.getSimpleName().toString(); + if ("eventObserver".equals(name)){ + foundSuper = true; + } + else if( "eventObserver1".equals(name)){ + foundIface = true; + } + } + assertTrue( "Observer method eventObserver inside Clazz1 is not found", foundSuper ); + assertTrue( "Observer method eventObserver1 inside Clazz1 is not found" , foundIface); + return null; + } + }); + } + + public void testAny()throws MetadataModelException, IOException, + InterruptedException + { + createQualifier("Binding"); + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {" + + " String value(); "+ + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperObject.java", + "package foo; " + + "public class SuperObject { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface.java", + "package foo; " + + "public class Iface { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/EventObject.java", + "package foo; " + + "public class EventObject extends SuperObject implements Iface { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/EventObject1.java", + "package foo; " + + "public class EventObject1 { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.inject.*; " + +"import jakarta.enterprise.inject.Any; " + + "import jakarta.enterprise.event.Event; " + + "public class TestClass {" + + " @Inject @Any Event event; " + + " @Inject Event event1; " + + " @Inject @Binding1(value=\"a\") @Any Event event2; " + + " @Inject @Binding @Any Event event3; " + + " @Inject @Binding Event event4; " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO,"foo/Clazz1.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; "+ + "import jakarta.enterprise.inject.Any; " + + "public class Clazz1 {" + + " public void eventObserver( @Observes SuperObject event ) {}" + + " public void eventObserver1( @Observes @Any Iface1 event ) {}" + + " public void eventObserver2( @Observes @Binding1(value=\"a\") EventObject event ) {}" + + " public void eventObserver3( @Observes @Binding1(value=\"a\") @Any EventObject event ) {}" + + "} "); + + TestUtilities.copyStringToFileObject(srcFO,"foo/Clazz2.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; "+ + "import jakarta.enterprise.inject.Any; " + + "public class Clazz2 {" + + " public void notEventObserver( @Observes @Any EventObject1 event ) {}" + + " public void notEventObserver1( @Observes EventObject1 event ) {}" + + "} "); + + inform("start @Any observer test"); + + MetadataModel metaModel = createBeansModel(); + metaModel.runReadAction(new MetadataModelAction() { + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType("foo.TestClass"); + Element clazz = ((DeclaredType) mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = new ArrayList( + children.size()); + for (Element element : children) { + if (element instanceof VariableElement) { + injectionPoints.add((VariableElement) element); + } + } + + assertEquals(5, injectionPoints.size()); + for (VariableElement variableElement : injectionPoints) { + String name = variableElement.getSimpleName().toString(); + if ( "event".equals(name)){ + checkEvent( variableElement , model , (DeclaredType) mirror); + } + else if ( "event1".equals(name)){ + checkEvent( variableElement , model , (DeclaredType) mirror); + } + else if ( "event2".equals(name)){ + checkEvent2( variableElement , model , (DeclaredType) mirror); + } + else if ( "event3".equals(name)){ + checkEvent3( variableElement , model , (DeclaredType) mirror); + } + else if ( "event4".equals(name)){ + checkEvent3( variableElement , model , (DeclaredType) mirror); + } + } + return null; + } + + + }); + + } + + private void checkEvent( VariableElement variableElement, + WebBeansModel model , DeclaredType parent ) + { + inform( "test " +variableElement.getSimpleName()+" field "); + List observers = model.getObservers(variableElement, parent); + assertEquals(4, observers.size()); + boolean observerFound = false; + boolean observer1Found = false; + boolean observer2Found = false; + boolean observer3Found = false; + for (ExecutableElement executableElement : observers) { + TypeElement typeElement = model.getCompilationController().getElementUtilities(). + enclosingTypeElement( executableElement); + String fqn = typeElement.getQualifiedName().toString(); + assertEquals( "foo.Clazz1", fqn); + String name = executableElement.getSimpleName().toString(); + if ( "eventObserver".equals(name)){ + observerFound = true; + } + else if ( "eventObserver1".equals(name)){ + observer1Found = true; + } + else if ( "eventObserver2".equals(name)){ + observer2Found = true; + } + else if ( "eventObserver3".equals(name)){ + observer3Found = true; + } + } + + assertTrue ("Observer method 'foo.Clazz1.eventObserver' is not found", observerFound); + assertTrue ("Observer method 'foo.Clazz1.eventObserver1' is not found", observer1Found); + assertTrue ("Observer method 'foo.Clazz1.eventObserver2' is not found", observer2Found); + assertTrue ("Observer method 'foo.Clazz1.eventObserver3' is not found", observer3Found); + } + + private void checkEvent2( VariableElement variableElement, + WebBeansModel model, DeclaredType parent ) + { + inform( "test " +variableElement.getSimpleName()+" field "); + List observers = model.getObservers(variableElement, parent); + assertEquals(2, observers.size()); + boolean observer2Found = false; + boolean observer3Found = false; + for (ExecutableElement executableElement : observers) { + TypeElement typeElement = model.getCompilationController().getElementUtilities(). + enclosingTypeElement( executableElement); + String fqn = typeElement.getQualifiedName().toString(); + assertEquals( "foo.Clazz1", fqn); + String name = executableElement.getSimpleName().toString(); + if ( "eventObserver2".equals(name)){ + observer2Found = true; + } + else if ( "eventObserver3".equals(name)){ + observer3Found = true; + } + } + + assertTrue ("Observer method 'foo.Clazz1.eventObserver2' is not found", observer2Found); + assertTrue ("Observer method 'foo.Clazz1.eventObserver3' is not found", observer3Found); + } + + private void checkEvent3( VariableElement variableElement, + WebBeansModel model, DeclaredType parent ) + { + inform( "test " +variableElement.getSimpleName()+" field "); + List observers = model.getObservers(variableElement, parent); + if ( observers.size() >0 ){ + ExecutableElement executableElement = observers.get( 0 ); + TypeElement typeElement = model.getCompilationController().getElementUtilities(). + enclosingTypeElement( executableElement); + String fqn = typeElement.getQualifiedName().toString(); + assertTrue( "Found unexpected observer method '"+fqn+"."+ + executableElement.getSimpleName(), false ); + } + } + + public void testRawParameterizedAssignability()throws MetadataModelException, + IOException, InterruptedException + { + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding {" + + " String value(); "+ + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/EventObject.java", + "package foo; " + + "public class EventObject extends SuperObject { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperObject.java", + "package foo; " + + "public class SuperObject { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/ChildObject.java", + "package foo; " + + "public class ChildObject extends EventObject { " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.inject.*; " + +"import jakarta.enterprise.inject.Any; " + + "import jakarta.enterprise.event.Event; " + + "import java.util.List; " + + "import java.util.Set; " + + "import java.util.Collection; " + + "public class TestClass {" + + " @Inject @Binding(value=\"a\") Event event; " + + " @Inject @Binding(value=\"b\") Event> event1; " + + " @Inject @Binding(value=\"c\") Event> event2; " + + " @Inject @Binding(value=\"d\") Event> event3; " + + " @Inject @Binding(value=\"e\") Event> event4; " + + " @Inject @Binding(value=\"f\") Event event5; " + + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; "+ + "public class Generic { " + + " public void eventObserver( @Observes @Binding(value=\"a\") T t){} "+ + "} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "import jakarta.enterprise.event.Observes; "+ + "import java.util.List; " + + "import java.util.Collection; " + + "import java.util.Set; " + +"public class Clazz { " + + " public void eventObserver( @Observes @Binding(value=\"b\") List list){} "+ + " public void eventObserver1( @Observes @Binding(value=\"c\") List list){} "+ + " public void eventObserver2( @Observes @Binding(value=\"d\") Collection list){} "+ + " public void eventObserver3( @Observes @Binding(value=\"e\") Collection list){} "+ + " public void eventObserver4( @Observes @Binding(value=\"f\") T t){} "+ + "} "); + + inform("start raw and parameterized assignability observer test"); + + MetadataModel metaModel = createBeansModel(); + metaModel.runReadAction(new MetadataModelAction() { + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType("foo.TestClass"); + Element clazz = ((DeclaredType) mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = new ArrayList( + children.size()); + for (Element element : children) { + if (element instanceof VariableElement) { + injectionPoints.add((VariableElement) element); + } + } + + assertEquals(6, injectionPoints.size()); + for (VariableElement variableElement : injectionPoints) { + String name = variableElement.getSimpleName().toString(); + if ( "event".equals(name)){ + commonAssagnabilityCheck(variableElement, model, + (DeclaredType) mirror, "foo.Generic" , + "eventObserver"); + } + else if ( "event1".equals(name)){ + commonAssagnabilityCheck(variableElement, model, + (DeclaredType) mirror, "foo.Clazz" , + "eventObserver"); + } + else if ( "event2".equals(name)){ + commonAssagnabilityCheck(variableElement, model, + (DeclaredType) mirror, "foo.Clazz" , + "eventObserver1"); + } + else if ( "event3".equals(name)){ + commonAssagnabilityCheck(variableElement, model, + (DeclaredType) mirror, "foo.Clazz" , + "eventObserver2"); + } + else if ( "event4".equals(name)){ + commonAssagnabilityCheck(variableElement, model, + (DeclaredType) mirror, "foo.Clazz" , + "eventObserver3"); + } + else if ( "event5".equals(name)){ + commonAssagnabilityCheck(variableElement, model, + (DeclaredType) mirror, "foo.Clazz" , + "eventObserver4"); + } + } + return null; + } + + }); + } + + private void commonAssagnabilityCheck( VariableElement variableElement, + WebBeansModel model, DeclaredType parent , String enclosingClassName , + String methodName ) + { + inform( "assignability test for " +variableElement.getSimpleName()+" field "); + List observers = model.getObservers(variableElement, parent); + assertEquals(1, observers.size()); + ExecutableElement executableElement = observers.get(0); + assertNotNull( executableElement ); + + String foundMethod = executableElement.getSimpleName().toString(); + assertEquals("Expected "+methodName+" observer but found :"+foundMethod, + methodName, foundMethod); + + TypeElement methodClass = model.getCompilationController().getElementUtilities(). + enclosingTypeElement( executableElement); + + + String name = methodClass.getQualifiedName().toString(); + assertEquals( "Enclosing type of observer method "+methodName+" should " + + "be "+enclosingClassName+" but found : "+name ,enclosingClassName , name); + } + + +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/ParametersTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/ParametersTest.java new file mode 100644 index 000000000000..761ebb4ddddd --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/ParametersTest.java @@ -0,0 +1,439 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.impl.model.results.DefinitionErrorResult; + + +/** + * @author ads + * + */ +public class ParametersTest extends CommonTestCase { + + public ParametersTest( String testName ) { + super(testName); + } + + public void testSimpleParameter() throws IOException, InterruptedException{ + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {" + + " String value(); "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding2 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class SuperClass { " + + " @Produces String productionField = \"\"; "+ + " @Produces @foo.Binding2 int[] productionMethod() { return null; } "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@foo.Binding1(value=\"a\") @foo.Binding2 " + + "public class One extends SuperClass {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class TestClass {" + + " @Inject void method1( @Binding2 SuperClass arg1 , " + + " @Binding1(\"a\") SuperClass arg2 ){} " + + " @Produces boolean method2( @Binding2 Two arg ){ return false;} "+ + " @Inject void method3( @Default SuperClass arg ){} "+ + " @Produces int method4( @Default String arg ){ return 0;} "+ + " @Inject void method5( @Binding2 int[] arg ){} " + + " void method6( @Binding2 int[] arg ){} "+ + " @Inject void method7( SuperClass arg ){} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "@foo.Binding2 " + + "public class Two extends SuperClass {}" ); + + inform( "start simple parameters test"); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof ExecutableElement ){ + List parameters = + ((ExecutableElement)element).getParameters(); + for (VariableElement variableElement : parameters) { + injectionPoints.add( variableElement ); + } + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + Element enclosingElement = element.getEnclosingElement(); + assert enclosingElement instanceof ExecutableElement; + ExecutableElement method = (ExecutableElement)enclosingElement; + names.add( method.getSimpleName()+ " " +element.getSimpleName()); + if ( method.getSimpleName().contentEquals("method1")){ + if ( element.getSimpleName().contentEquals("arg1")){ + assertFindParameterResultInjectables(element, provider, "foo.One", "foo.Two"); + assertFindParameterResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("arg2")){ + assertFindParameterResultInjectables(element, provider, "foo.One"); + assertFindParameterResultProductions(element, provider); + } + } + else if (method.getSimpleName().contentEquals("method2") ){ + assertFindParameterResultInjectables(element, provider, "foo.Two"); + assertFindParameterResultProductions(element, provider); + } + else if (method.getSimpleName().contentEquals("method3") ){ + assertFindParameterResultInjectables(element, provider, "foo.SuperClass"); + assertFindParameterResultProductions(element, provider); + } + else if (method.getSimpleName().contentEquals("method4") ){ + DependencyInjectionResult result = provider.findParameterInjectable(element, null, new AtomicBoolean(false)); + assertResultInjectables(result); + assertResultProductions(result, true, "productionField"); + } + else if (method.getSimpleName().contentEquals("method5") ){ + assertFindParameterResultInjectables(element, provider); + assertFindParameterResultProductions(element, provider, "productionMethod"); + } + else if (method.getSimpleName().contentEquals("method6") ){ + DependencyInjectionResult result = provider.findParameterInjectable(element, null, new AtomicBoolean(false)); + /* Method has no any special annotation. It's argument is not injection point.*/ + assertTrue( result instanceof DefinitionErrorResult ); + } + else if (method.getSimpleName().contentEquals("method7") ){ + assertFindParameterResultInjectables(element, provider, "foo.SuperClass"); + assertFindParameterResultProductions(element, provider); + } + } + + assert names.contains("method1 arg1"); + assert names.contains("method1 arg2"); + assert names.contains("method2 arg"); + assert names.contains("method3 arg"); + assert names.contains("method4 arg"); + assert names.contains("method6 arg"); + return null; + } + }); + } + + public void testDisposesParameter() throws IOException, InterruptedException{ + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {" + + " String value(); "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding2 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class SuperClass { " + + " @Produces @Binding2 String getText(){ return null;} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@foo.Binding1(value=\"a\") @foo.Binding2 " + + "public class One extends SuperClass {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class TestClass {" + + " @Produces @Binding2 int getIndex(){ return 0;} "+ + " @Produces @Binding1(\"a\") boolean isNull(){ return false;} "+ + " @Produces String get(){ return null;} "+ + + " void clean(@Disposes @Binding2 int index , String text){} "+ + " void stopped(@Disposes @Binding1(\"a\") boolean isNull ){} "+ + " void close(@Disposes @Binding1(\"a\") SuperClass clazz){} "+ + " void inform(@Disposes @Binding2 String text){} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "@foo.Binding2 " + + "public class Two extends SuperClass {}" ); + + inform( "start disposes parameters test"); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof ExecutableElement ){ + List parameters = + ((ExecutableElement)element).getParameters(); + for (VariableElement variableElement : parameters) { + injectionPoints.add( variableElement ); + } + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + Element enclosingElement = element.getEnclosingElement(); + assert enclosingElement instanceof ExecutableElement; + ExecutableElement method = (ExecutableElement)enclosingElement; + names.add( method.getSimpleName()+ " " +element.getSimpleName()); + if ( method.getSimpleName().contentEquals("clean")){ + if ( element.getSimpleName().contentEquals("index")){ + assertFindParameterResultInjectables(element, provider); + assertFindParameterResultProductions(element, provider, "getIndex"); + } + else if ( element.getSimpleName().contentEquals("text")){ + assertFindParameterResultInjectables(element, provider); + assertFindParameterResultProductions(element, provider, "get"); + } + } + else if (method.getSimpleName().contentEquals("stopped") ){ + assertFindParameterResultInjectables(element, provider); + assertFindParameterResultProductions(element, provider, "isNull"); + } + else if (method.getSimpleName().contentEquals("close") ){ + assertFindParameterResultInjectables(element, provider); + assertFindParameterResultProductions(element, provider); + } + else if (method.getSimpleName().contentEquals("inform") ){ + assertFindParameterResultInjectables(element, provider); + assertFindParameterResultProductions(element, provider); + } + } + + assert names.contains("clean index"); + assert names.contains("clean text"); + assert names.contains("stopped isNull"); + assert names.contains("close clazz"); + assert names.contains("inform text"); + return null; + } + }); + } + + public void testObservesParameter() throws IOException, InterruptedException{ + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {" + + " String value(); "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding2 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class SuperClass { " + + " @Produces @Default String getText(){ return null;} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@foo.Binding1(value=\"a\") @foo.Binding2 " + + "public class One extends SuperClass {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SomeEvent.java", + "package foo; " + + "public class SomeEvent {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.enterprise.event.*; "+ + "public class TestClass {" + + " void method1(@Observes @Binding2 SomeEvent , String text){} "+ + " void method2(@Observes @Binding1(\"a\") SomeEvent, " + + " @foo.Binding1(\"a\") @foo.Binding2 SuperClass clazz){} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "@foo.Binding2 " + + "public class Two extends SuperClass {}" ); + + inform( "start observes parameters test"); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof ExecutableElement ){ + List parameters = + ((ExecutableElement)element).getParameters(); + for (VariableElement variableElement : parameters) { + injectionPoints.add( variableElement ); + } + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + Element enclosingElement = element.getEnclosingElement(); + assert enclosingElement instanceof ExecutableElement; + ExecutableElement method = (ExecutableElement)enclosingElement; + names.add( method.getSimpleName()+ " " +element.getSimpleName()); + if ( method.getSimpleName().contentEquals("method1")){ + if ( element.getSimpleName().contentEquals("text")){ + assertFindParameterResultInjectables(element, provider); + assertFindParameterResultProductions(element, provider, "getText"); + names.add("method1 text"); + } + } + else if (method.getSimpleName().contentEquals("method2") ){ + if ( element.getSimpleName().contentEquals("clazz")){ + assertFindParameterResultInjectables(element, provider, "foo.One"); + assertFindParameterResultProductions(element, provider); + names.add("method2 clazz"); + } + } + } + + assert names.contains("method1 text"); + assert names.contains("method2 clazz"); + return null; + } + }); + } + +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/ProgrammaticTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/ProgrammaticTest.java new file mode 100644 index 000000000000..62ebf596914e --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/ProgrammaticTest.java @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult.ResultKind; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class ProgrammaticTest extends CommonTestCase { + + public ProgrammaticTest( String testName ) { + super(testName); + } + + public void testProgrammatic() throws IOException{ + createQualifier("Binding"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@Binding "+ + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "@Binding "+ + "public class Two extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Binding "+ + "@Alternative "+ + "public class Three extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class TestClass {" + + " @Inject @Binding Instance myField1; "+ + " @Inject @Binding One myField2; "+ + "}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myField1")){ + assertTrue ( "myField1 should be recognized as programmatic " + + "injection point",model.isDynamicInjectionPoint(element)); + DependencyInjectionResult injectables = model.lookupInjectables(element, null, new AtomicBoolean(false)); + ResultKind kind = injectables.getKind(); + assertEquals(ResultKind.INJECTABLES_RESOLVED, kind); + check(element, injectables, kind); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + assertFalse ( "myField2 should be recognized as programmatic " + + "injection point",model.isDynamicInjectionPoint(element)); + DependencyInjectionResult injectables = model.lookupInjectables(element, null, new AtomicBoolean(false)); + ResultKind kind = injectables.getKind(); + assertEquals(ResultKind.RESOLUTION_ERROR, kind); + assertTrue( injectables instanceof DependencyInjectionResult.Error ); + check(element, injectables, kind); + } + } + + assert names.contains("myField1"); + assert names.contains("myField2"); + return null; + } + + + }); + } + + private void check( VariableElement element, DependencyInjectionResult injectables, + ResultKind kind ) + { + assertTrue( injectables instanceof DependencyInjectionResult.ApplicableResult ); + assertTrue( injectables instanceof DependencyInjectionResult.ResolutionResult ); + Set typeElements = + ((DependencyInjectionResult.ApplicableResult)injectables).getTypeElements(); + assertEquals("Incorrect number of eligible elemets are found", + 3, typeElements.size()); + for( TypeElement type : typeElements ){ + if ( type.getQualifiedName().contentEquals("foo.Three")){ + assertTrue( "foo.Three element is enabled", + ((DependencyInjectionResult.ApplicableResult)injectables).isDisabled(element)); + } + } + } + +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/QualifiersTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/QualifiersTest.java new file mode 100644 index 000000000000..a703dbb72d6c --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/QualifiersTest.java @@ -0,0 +1,379 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; +import java.io.IOException; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + +/** + * @author ads + * + */ +public class QualifiersTest extends CommonTestCase { + + public QualifiersTest( String testName ) { + super(testName); + } + + public void testSimpleQualifiers() throws IOException { + createQualifier("Binding1"); + createQualifier("Binding2"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "@Binding1 @Binding2 @Default "+ + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "public class Two extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.inject.*; "+ + "@Named "+ + "public class Three extends Two {}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.One" ); + Element clazz = ((DeclaredType)mirror).asElement(); + + List qualifiers = model.getQualifiers(clazz, true); + assertEquals( "foo.One should have exactly 3 qualifiers", 3, qualifiers.size()); + assertFalse( "foo.One shoudn't have implicitely defined @Default qualifier", + model.hasImplicitDefaultQualifier(clazz) ); + + mirror = model.resolveType( "foo.Two" ); + clazz = ((DeclaredType)mirror).asElement(); + + qualifiers = model.getQualifiers(clazz, true ); + assertEquals( "foo.Two shouldn't have qualifiers", 0, qualifiers.size()); + assertTrue( "foo.Two has implicitely defined @Default qualifier", + model.hasImplicitDefaultQualifier(clazz) ); + + mirror = model.resolveType( "foo.Three" ); + clazz = ((DeclaredType)mirror).asElement(); + + qualifiers = model.getQualifiers(clazz, true ); + assertEquals( "foo.Three has exactly one qualifier", 1, + qualifiers.size()); + assertTrue( "foo.Three has implicitely defined @Default qualifier", + model.hasImplicitDefaultQualifier(clazz) ); + return null; + } + }); + } + + public void testDefaultInheritance() throws IOException { + createQualifier("Binding1"); + createQualifier("Binding2"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding3.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Inherited "+ + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding3 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "@Binding1 @Default "+ + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "public class Two extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.inject.*; "+ + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "@Binding2 "+ + "public class Three extends Two {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One1.java", + "package foo; " + + "public class One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "@Binding1 "+ + "public class Two1 extends One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "public class Three1 extends Two1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One2.java", + "package foo; " + + "@Binding3 "+ + "public class One2 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two2.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class Two2 extends One2 {}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.Two" ); + Element clazz = ((DeclaredType)mirror).asElement(); + + List qualifiers = model.getQualifiers(clazz, true); + assertEquals( "foo.Two should have exactly 2 qualifiers", 2, + qualifiers.size()); + assertTrue( "foo.Two shouldn't have implicitely defined @Default qualifier", + model.hasImplicitDefaultQualifier(clazz) ); + + mirror = model.resolveType( "foo.Three" ); + clazz = ((DeclaredType)mirror).asElement(); + + qualifiers = model.getQualifiers(clazz, true); + assertEquals( "foo.Three has exactly three qualifier", + 3, qualifiers.size()); + assertFalse( "foo.Three shouldn't have implicitely defined @Default qualifier", + model.hasImplicitDefaultQualifier(clazz) ); + + mirror = model.resolveType( "foo.Two1" ); + clazz = ((DeclaredType)mirror).asElement(); + + qualifiers = model.getQualifiers(clazz, true); + assertEquals( "foo.Two1 has exactly one qualifier", 1, + qualifiers.size()); + assertFalse( "foo.Two1 shouldn't have implicitely defined @Default qualifier", + model.hasImplicitDefaultQualifier(clazz) ); + + mirror = model.resolveType( "foo.Three1" ); + clazz = ((DeclaredType)mirror).asElement(); + + qualifiers = model.getQualifiers(clazz, true); + assertEquals( "foo.Three1 has exactly one qualifier", 1, + qualifiers.size()); + assertTrue( "foo.Three1 has implicitely defined @Default qualifier", + model.hasImplicitDefaultQualifier(clazz) ); + + mirror = model.resolveType( "foo.Two2" ); + clazz = ((DeclaredType)mirror).asElement(); + + qualifiers = model.getQualifiers(clazz, true ); + assertEquals( "foo.Three1 has exactly one qualifier", 1, + qualifiers.size()); + assertFalse( "foo.Three1 has implicitely defined @Default qualifier", + model.hasImplicitDefaultQualifier(clazz) ); + return null; + } + }); + } + + public void testInheritance() throws IOException { + createQualifier("Binding1"); + createQualifier("Binding2"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding3.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Inherited "+ + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding3 {} "); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@Binding1 "+ + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "@Binding3 "+ + "public class Two extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "@Binding2 "+ + "public class Three extends Two {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Four.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "@Binding2 "+ + "public class Four extends Two {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Five.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "public class Five extends Three {}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.Two" ); + Element clazz = ((DeclaredType)mirror).asElement(); + + List qualifiers = model.getQualifiers(clazz, true); + assertEquals( "foo.Two should have exactly 2 qualifiers", 2, + qualifiers.size()); + + mirror = model.resolveType( "foo.Three" ); + clazz = ((DeclaredType)mirror).asElement(); + + qualifiers = model.getQualifiers(clazz, true); + assertEquals( "foo.Three has exactly two qualifier", + 2, qualifiers.size()); + + mirror = model.resolveType( "foo.Four" ); + clazz = ((DeclaredType)mirror).asElement(); + + qualifiers = model.getQualifiers(clazz, true); + assertEquals( "foo.Four has exactly three qualifier", 3, + qualifiers.size()); + + mirror = model.resolveType( "foo.Five" ); + clazz = ((DeclaredType)mirror).asElement(); + + qualifiers = model.getQualifiers(clazz, true); + assertEquals( "foo.Three1 has exactly two qualifier", 2, + qualifiers.size()); + + return null; + } + }); + } + + public void testMethodInheritance() throws IOException { + createQualifier("Binding1"); + createQualifier("Binding2"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class One {" + + " @Produces @Binding1 public int method() {return 0;} "+ + " @Produces @Binding1 public String operation() {return \"\";} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class Two extends One {" + + " @Produces @Specializes @Binding2 public int method() {return 0;} "+ + " @Produces public @Binding2 String operation() {return \"\";} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class Three extends Two {" + + " @Produces @Specializes public int method() {return 0;} "+ + " @Produces @Specializes public String operation() {return \"\";} "+ + "}" ); + + TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.Three" ); + Element clazz = ((DeclaredType)mirror).asElement(); + + Set names = new HashSet(); + List children = clazz.getEnclosedElements(); + for (Element element : children) { + String name = element.getSimpleName().toString() ; + names.add(name ); + assertTrue ( element instanceof ExecutableElement ); + + List qualifiers = model.getQualifiers(element, true); + if ( name.equals("method")){ + assertEquals( "Method 'method' should have exactly 2 qualifiers", + 2, qualifiers.size()); + } + else if ( name.equals("operation")){ + assertEquals( "Method 'method' should have exactly 1 qualifiers", + 1, qualifiers.size()); + } + } + + assertTrue( names.contains( "method")); + assertTrue( names.contains( "operation")); + + return null; + } + }); + } +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/RawParameterizedAssignabilityTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/RawParameterizedAssignabilityTest.java new file mode 100644 index 000000000000..d20da6515184 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/RawParameterizedAssignabilityTest.java @@ -0,0 +1,317 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class RawParameterizedAssignabilityTest extends CommonTestCase { + + public RawParameterizedAssignabilityTest( String testName ) { + super(testName); + } + + public void testGenerics() throws IOException, InterruptedException { + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomBinding.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface CustomBinding {" + + " String value(); "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class CustomClass {" + + " @Inject @CustomBinding(\"a\") Generic myField1; "+ + " @Inject @CustomBinding(\"b\") Generic myField2; "+ + " @Inject @CustomBinding(\"b\") Generic myField3; "+ + " @Inject @CustomBinding(\"c\") Generic myField4; "+ + " @Inject @CustomBinding(\"b\") Generic myField5; "+ + " @Inject @CustomBinding(\"d\") Generic4 myField6; "+ + " @Inject @CustomBinding(\"e\") Generic5 myField7; "+ + " @Inject @CustomBinding(\"d\") Generic4 myField8; "+ + " @Inject @CustomBinding(\"d\") Generic4 myField9; "+ + " @Inject @CustomBinding(\"d\") Generic myField10; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic.java", + "package foo; " + + " @CustomBinding(\"a\") "+ + "public class Generic {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic1.java", + "package foo; " + + " @CustomBinding(\"b\") "+ + "public class Generic1 extends Generic {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "public class One {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "public class Two extends One {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "public class Three extends One {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic2.java", + "package foo; " + + " @CustomBinding(\"b\") "+ + "public class Generic2 extends Generic {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic3.java", + "package foo; " + + " @CustomBinding(\"c\") "+ + "public class Generic3 extends Generic {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic4.java", + "package foo; " + + " @CustomBinding(\"d\") "+ + "public class Generic4 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic5.java", + "package foo; " + + " @CustomBinding(\"e\") "+ + "public class Generic5 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic6.java", + "package foo; " + + " @CustomBinding(\"a\") "+ + "public class Generic6 extends Generic {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic7.java", + "package foo; " + + " @CustomBinding(\"d\") "+ + "public class Generic7 extends Generic {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic8.java", + "package foo; " + + " @CustomBinding(\"d\") "+ + "public class Generic8 extends Generic {}"); + + inform("start generic types tests"); + + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.CustomClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if (element instanceof VariableElement) { + injectionPoints.add( (VariableElement)element ); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myField1")){ + assertFindVariableResultInjectables(element, provider, "foo.Generic", + "foo.Generic6"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + assertFindVariableResultInjectables(element, provider, "foo.Generic1"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField3")){ + assertFindVariableResultInjectables(element, provider, "foo.Generic2"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField4")){ + assertFindVariableResultInjectables(element, provider, "foo.Generic3"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField5")){ + assertFindVariableResultInjectables(element, provider, "foo.Generic1"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField6")){ + assertFindVariableResultInjectables(element, provider, "foo.Generic4"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField7")){ + assertFindVariableResultInjectables(element, provider, "foo.Generic5"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField8")){ + assertFindVariableResultInjectables(element, provider, "foo.Generic4"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField9")){ + assertFindVariableResultInjectables(element, provider, "foo.Generic4"); + assertFindVariableResultProductions(element, provider); + } + else if ( element.getSimpleName().contentEquals("myField10")){ + assertFindVariableResultInjectables(element, provider, "foo.Generic7"); + assertFindVariableResultProductions(element, provider); + } + } + + assert names.contains("myField1"); + assert names.contains("myField2"); + assert names.contains("myField3"); + assert names.contains("myField4"); + assert names.contains("myField5"); + assert names.contains("myField6"); + assert names.contains("myField7"); + assert names.contains("myField8"); + assert names.contains("myField9"); + assert names.contains("myField10"); + + return null; + } + }); + } + + public void testProductions() throws IOException, InterruptedException { + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomBinding.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface CustomBinding {" + + " String value(); "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.util.*; "+ + "public class CustomClass {" + + " @Inject @CustomBinding(\"a\") Class myField1; "+ + " @Inject @CustomBinding(\"b\") List myField2; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import java.util.*; "+ + "public class Generic {" + + " @Produces @CustomBinding(\"a\") Class getClass(){ " + + " return null; " + + "}"+ + " @Produces @CustomBinding(\"b\") List myList; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "public class One {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "public class Two extends One {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class Generic1 extends Generic {" + + "}"); + + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.CustomClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if (element instanceof VariableElement) { + injectionPoints.add( (VariableElement)element ); + } + } + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + // Productions are not inherited by child classes. + if ( element.getSimpleName().contentEquals("myField1")){ + assertFindVariableResultInjectables(element, provider); + assertFindAllProductions(element, provider, "getClass", + "foo.Generic" ); + } + if ( element.getSimpleName().contentEquals("myField2")){ + assertFindVariableResultInjectables(element, provider); + assertFindAllProductions(element, provider, + "myList", "foo.Generic"); + } + } + + assert names.contains("myField1"); + assert names.contains("myField2"); + + return null; + } + }); + } + +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/ScopeTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/ScopeTest.java new file mode 100644 index 000000000000..ad31de342028 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/ScopeTest.java @@ -0,0 +1,318 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; + +import javax.lang.model.element.Element; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.CdiException; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class ScopeTest extends CommonTestCase { + + public ScopeTest( String testName ) { + super(testName); + } + + public void testInheritedScope() throws IOException{ + + TestUtilities.copyStringToFileObject(srcFO, "foo/SuperClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.enterprise.context.SessionScoped; "+ + "@SessionScoped "+ + "public class SuperClass { " + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/ChildClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.enterprise.context.ApplicationScoped; "+ + "@ApplicationScoped "+ + "public class ChildClass extends SuperClass{ " + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/SubClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class SubClass extends ChildClass{ " + + "}" ); + + final TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.SuperClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + checkScope(model, clazz, "jakarta.enterprise.context.SessionScoped"); + + mirror = model.resolveType( "foo.ChildClass" ); + clazz = ((DeclaredType)mirror).asElement(); + checkScope(model, clazz, "jakarta.enterprise.context.ApplicationScoped"); + + mirror = model.resolveType( "foo.SubClass" ); + clazz = ((DeclaredType)mirror).asElement(); + checkScope(model, clazz, "jakarta.enterprise.context.ApplicationScoped"); + + return null; + } + + }); + } + + public void testDependentScope() throws IOException{ + + TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "public class Clazz { " + + "}" ); + final TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.Clazz" ); + Element clazz = ((DeclaredType)mirror).asElement(); + checkScope(model, clazz, "jakarta.enterprise.context.Dependent"); + return null; + } + }); + } + + public void testSterotypedScope() throws IOException{ + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.enterprise.context.SessionScoped; "+ + "@Stereotype "+ + "@SessionScoped "+ + "@Target({TYPE}) "+ + "@Retention(RUNTIME) "+ + "public @interface Stereotype1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Class1.java", + "package foo; " + + "@Stereotype1 "+ + "public class Class1 { " + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Class2.java", + "package foo; " + + "import jakarta.enterprise.context.ApplicationScoped; "+ + "@Stereotype1 "+ + "@ApplicationScoped "+ + "public class Class2 { " + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Class3.java", + "package foo; " + + "import jakarta.enterprise.context.ApplicationScoped; "+ + "@Stereotype1 "+ + "public class Class3 extends Class2 { " + + "}" ); + + final TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.Class1" ); + Element clazz = ((DeclaredType)mirror).asElement(); + checkScope(model, clazz, "jakarta.enterprise.context.SessionScoped"); + + mirror = model.resolveType( "foo.Class2" ); + clazz = ((DeclaredType)mirror).asElement(); + checkScope(model, clazz, "jakarta.enterprise.context.ApplicationScoped"); + + mirror = model.resolveType( "foo.Class3" ); + clazz = ((DeclaredType)mirror).asElement(); + checkScope(model, clazz, "jakarta.enterprise.context.ApplicationScoped"); + return null; + } + }); + } + + public void testCustomScope() throws IOException{ + + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomScope.java", + "package foo; " + + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.enterprise.context.*; "+ + "@NormalScope "+ + "@Target({TYPE,METHOD,FIELD}) "+ + "@Retention(RUNTIME) "+ + "@Inherited "+ + "public @interface CustomScope {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Clazz.java", + "package foo; " + + "@CustomScope "+ + "public class Clazz { " + + "}" ); + final TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.Clazz" ); + Element clazz = ((DeclaredType)mirror).asElement(); + checkScope(model, clazz, "foo.CustomScope"); + return null; + } + }); + } + + public void testDefaultScope() throws IOException{ + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.enterprise.context.SessionScoped; "+ + "@Stereotype "+ + "@SessionScoped "+ + "@Target({TYPE}) "+ + "@Retention(RUNTIME) "+ + "public @interface Stereotype1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.enterprise.context.SessionScoped; "+ + "@Stereotype "+ + "@SessionScoped "+ + "@Target({TYPE}) "+ + "@Retention(RUNTIME) "+ + "public @interface Stereotype2 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Stereotype3.java", + "package foo; " + + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.enterprise.context.ApplicationScoped; "+ + "@Stereotype "+ + "@ApplicationScoped "+ + "@Target({TYPE}) "+ + "@Retention(RUNTIME) "+ + "public @interface Stereotype3 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Class1.java", + "package foo; " + + "@Stereotype1 "+ + "@Stereotype2 "+ + "public class Class1 { " + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Class2.java", + "package foo; " + + "@Stereotype1 "+ + "@Stereotype3 "+ + "public class Class2 { " + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Class3.java", + "package foo; " + + "import jakarta.enterprise.context.ApplicationScoped; "+ + "@Stereotype1 "+ + "@Stereotype3 "+ + "@ApplicationScoped "+ + "public class Class3 { " + + "}" ); + + + final TestWebBeansModelImpl modelImpl = createModelImpl(true ); + MetadataModel testModel = modelImpl.createTestModel(); + testModel.runReadAction( new MetadataModelAction(){ + + @Override + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.Class1" ); + Element clazz = ((DeclaredType)mirror).asElement(); + checkScope(model, clazz, "jakarta.enterprise.context.SessionScoped"); + + mirror = model.resolveType( "foo.Class3" ); + clazz = ((DeclaredType)mirror).asElement(); + checkScope(model, clazz, "jakarta.enterprise.context.ApplicationScoped"); + + mirror = model.resolveType( "foo.Class2" ); + clazz = ((DeclaredType)mirror).asElement(); + boolean exception = false; + + try { + model.getScope(clazz); + } + catch(CdiException e ){ + exception = true; + } + assertTrue( "Class2 has no explicit Scope but has different " + + "Stereotypes with different default Scopes. So it has no" + + " default scope and this is a problem", exception ); + return null; + } + }); + } + + private void checkScope(WebBeansModel model , Element element, + String fqn ){ + try { + String scope = model.getScope(element); + assertEquals("Not expected scope type", fqn, scope); + } + catch ( CdiException e ){ + throw new RuntimeException( e ); + } + } +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/SpecializesTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/SpecializesTest.java new file mode 100644 index 000000000000..d6b0c53b84d3 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/SpecializesTest.java @@ -0,0 +1,592 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class SpecializesTest extends CommonTestCase { + + public SpecializesTest( String testName ) { + super(testName); + } + + public void testSimpleTypeSpecializes() throws IOException, InterruptedException{ + + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomBinding.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface CustomBinding {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class CustomClass {" + + " @Inject @CustomBinding One myField; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "@CustomBinding "+ + "public class Two extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "public class Three extends Two {}" ); + + inform("start simple specializes test"); + + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.CustomClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + for (Element element : children) { + if (element instanceof VariableElement) { + assert element.getSimpleName().contentEquals("myField"); + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.Two", "foo.Three"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + } + return null; + } + }); + } + + public void testMergeBindingsSpecializes() throws IOException, InterruptedException{ + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomBinding.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface CustomBinding {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding2 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class CustomClass {" + + " @Inject @CustomBinding @Binding1 @Binding2 One myField; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "@Binding1 " + + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "@Binding2 "+ + "public class Two extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "@CustomBinding "+ + "public class Three extends Two {}" ); + + inform("start merged specializes test"); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.CustomClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + for (Element element : children) { + if (element instanceof VariableElement) { + assert element.getSimpleName().contentEquals("myField"); + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.Three"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + } + return null; + } + }); + } + + public void testDefaultSpecializes() throws IOException, InterruptedException{ + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding2 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class CustomClass {" + + " @Inject @Default Two myField1; "+ + " @Inject Three myField2; "+ + " @Inject @Default @Binding2 @Binding1 One1 myField3; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Default " + + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "@Binding2 "+ + "public class Two extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One1.java", + "package foo; " + + "@Binding1 "+ + "public class One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "@Binding2 "+ + "public class Two1 extends One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "@Specializes "+ + "public class Three extends Two1 {}" ); + + inform("start @Default specializes test"); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.CustomClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + Set names = new HashSet(); + for (Element element : children) { + if ( element instanceof VariableElement ){ + names.add( element.getSimpleName().toString()); + if ( element.getSimpleName().contentEquals("myField1")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.Two"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.Three"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + else if ( element.getSimpleName().contentEquals("myField3")){ + assertFindVariableResultInjectables((VariableElement)element, provider, "foo.Three"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + } + } + assert names.contains("myField1"); + assert names.contains("myField2"); + assert names.contains("myField3"); + return null; + } + }); + } + + public void testSimpleProductionSpecializes() throws IOException, InterruptedException{ + + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomBinding.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface CustomBinding {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomClass.java", + "package foo; " + + "import jakarta.inject.*; "+ + "public class CustomClass {" + + " @Inject @CustomBinding int myField; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class One {" + + " @CustomBinding @Produces int getIndex(){ return 0;} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class Two extends One {" + + " @Produces @Specializes int getIndex(){return 0;} "+ + "}" ); + + inform("start simple specializes test for production methods"); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.CustomClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + for (Element element : children) { + if (element instanceof VariableElement) { + assert element.getSimpleName().contentEquals("myField"); + assertFindVariableResultInjectables((VariableElement)element, provider); + assertFindVariableResultProductions((VariableElement)element, provider, "getIndex", "getIndex"); + } + } + return null; + } + }); + } + + public void testMergeProductionSpecializes() throws IOException, InterruptedException{ + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomBinding.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface CustomBinding {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding2 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomClass.java", + "package foo; " + + "import jakarta.inject.*; "+ + "public class CustomClass {" + + " @Inject @CustomBinding @Binding1 @Binding2 int myField; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class One {" + + " @Produces @CustomBinding int getIndex(){ return 0; } " + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class Two extends One {" + + " @Produces @Specializes @Binding1 int getIndex(){ return 0; } " + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class Three extends Two {" + + " @Produces @Specializes @Binding2 int getIndex(){ return 0; } " + + "}" ); + + inform("start merged specializes test for production method"); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( + new MetadataModelAction() { + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model + .resolveType("foo.CustomClass"); + Element clazz = ((DeclaredType) mirror).asElement(); + List children = clazz + .getEnclosedElements(); + for (Element element : children) { + if (element instanceof VariableElement) { + assert element.getSimpleName().contentEquals( + "myField"); + assertFindVariableResultInjectables((VariableElement)element, provider); + assertFindVariableResultProductions((VariableElement)element, provider, "getIndex"); + } + } + return null; + } + }); + } + + public void testDefaultProductionSpecializes() throws IOException, InterruptedException{ + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding1.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding1 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Binding2.java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Binding2 {}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/CustomClass.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "public class CustomClass {" + + " @Inject @Default @Binding1 int myField1; "+ + " @Inject @Default @Binding2 @Binding1 boolean myField2; "+ + "}"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class One {" + + " @Produces @Default int getIndex(){ return 0;} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class Two extends One {" + + " @Produces @Specializes @Binding1 int getIndex(){ return 0;} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class One1 {" + + " @Produces @Binding1 boolean isNull(){ return true;} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two1.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class Two1 extends One1 {" + + " @Produces @Specializes @Binding2 boolean isNull(){ return true;} "+ + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.*; "+ + "public class Three extends Two1 {" + + " @Produces @Specializes boolean isNull(){ return true;} "+ + "}" ); + + inform("start @Default specializes test for production method"); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.CustomClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + Set names = new HashSet(); + for (Element element : children) { + if ( element instanceof VariableElement ){ + names.add( element.getSimpleName().toString()); + if ( element.getSimpleName().contentEquals("myField1")){ + assertFindVariableResultInjectables((VariableElement)element, provider); + assertFindVariableResultProductions((VariableElement)element, provider, "getIndex"); + } + else if ( element.getSimpleName().contentEquals("myField2")){ + assertFindVariableResultInjectables((VariableElement)element, provider); + assertFindVariableResultProductions((VariableElement)element, provider, "isNull"); + } + } + } + assert names.contains("myField1"); + assert names.contains("myField2"); + return null; + } + }); + } + +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/TestBeansModelImpl.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/TestBeansModelImpl.java new file mode 100644 index 000000000000..8dcc18be36ea --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/TestBeansModelImpl.java @@ -0,0 +1,165 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.logging.Logger; +import org.netbeans.modules.jakarta.web.beans.api.model.BeanArchiveType; + +import org.netbeans.modules.jakarta.web.beans.api.model.BeansModel; +import org.netbeans.modules.jakarta.web.beans.xml.AlternativeElement; +import org.netbeans.modules.jakarta.web.beans.xml.Alternatives; +import org.netbeans.modules.jakarta.web.beans.xml.BeanClassContainer; +import org.netbeans.modules.jakarta.web.beans.xml.Decorators; +import org.netbeans.modules.jakarta.web.beans.xml.Interceptors; +import org.netbeans.modules.jakarta.web.beans.xml.BeanClass; +import org.netbeans.modules.jakarta.web.beans.xml.Stereotype; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansModelFactory; +import org.netbeans.modules.xml.retriever.catalog.Utilities; +import org.netbeans.modules.xml.xam.ModelSource; +import org.netbeans.modules.xml.xam.locator.CatalogModelException; +import org.omg.PortableInterceptor.Interceptor; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +class TestBeansModelImpl implements BeansModel { + + TestBeansModelImpl(FileObject sourceRoot ) + { + FileObject fileObject = sourceRoot.getFileObject("beans.xml"); + if ( fileObject != null ) { + myModel = WebBeansModelFactory.getInstance().getModel( + getModelSource(fileObject)); + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.BeansModel#getAlternativeClasses() + */ + @Override + public Set getAlternativeClasses() { + Set result = new HashSet(); + for( BeanClass clazz : getAlternativeElement(BeanClass.class)){ + result.add( clazz.getBeanClass() ); + } + return result; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.BeansModel#getAlternativeStereotypes() + */ + @Override + public Set getAlternativeStereotypes() { + Set result = new HashSet(); + for( Stereotype stereotype : getAlternativeElement(Stereotype.class)){ + result.add( stereotype.getStereotype() ); + } + return result; + } + + private List getAlternativeElement( + Class clazz) + { + if ( myModel == null ){ + return Collections.emptyList(); + } + List children = + myModel.getBeans().getChildren( Alternatives.class); + List result = new LinkedList(); + for (Alternatives alternative : children) { + List elements = alternative.getChildren( clazz ); + result.addAll( elements ); + } + return result; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.BeansModel#getDecoratorClasses() + */ + @Override + public LinkedHashSet getDecoratorClasses() { + LinkedHashSet result = new LinkedHashSet(); + if ( myModel == null ){ + return result; + } + List children = + myModel.getBeans().getChildren( Decorators.class); + collectBeanClasses(result, children); + return result; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.BeansModel#getIntercetorClasses() + */ + @Override + public LinkedHashSet getInterceptorClasses() { + LinkedHashSet result = new LinkedHashSet(); + if ( myModel == null ){ + return result; + } + List children = + myModel.getBeans().getChildren( Interceptors.class); + collectBeanClasses(result, children); + return result; + } + + private void collectBeanClasses( + LinkedHashSet resultCollection, List containers ) + { + for (T container : containers) { + List beansClasses = container.getBeansClasses(); + for (BeanClass beanClass : beansClasses) { + resultCollection.add(beanClass.getBeanClass()); + } + } + } + + private ModelSource getModelSource( FileObject fileObject ) + { + try { + return Utilities.createModelSource( fileObject,false); + } catch (CatalogModelException ex) { + Logger.getLogger("global").log(java.util.logging.Level.SEVERE, + ex.getMessage(), ex); // NOI18N + } + return null; + } + + private WebBeansModel myModel; + + @Override + public BeanArchiveType getBeanArchiveType() { + return BeanArchiveType.EXPLICIT; + } + + @Override + public boolean isCdi11OrLater() { + return true; + } +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/TestWebBeansModelImpl.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/TestWebBeansModelImpl.java new file mode 100644 index 000000000000..4bbd4aa08f04 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/TestWebBeansModelImpl.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.support.annotation.AnnotationModelHelper; +import org.netbeans.modules.j2ee.metadata.model.spi.MetadataModelFactory; +import org.netbeans.modules.jakarta.web.beans.api.model.BeansModel; +import org.netbeans.modules.jakarta.web.beans.api.model.ModelUnit; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.impl.model.WebBeansModelImplementation; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +public class TestWebBeansModelImpl extends WebBeansModelImplementation { + + TestWebBeansModelImpl(ModelUnit unit){ + this(unit, false); + myProvider = new TestWebBeansModelProviderImpl( this ); + } + + TestWebBeansModelImpl(ModelUnit unit, boolean fullModel ){ + super(unit); + myProvider = new TestWebBeansModelProviderImpl( this ); + isFullModel = fullModel; + if ( fullModel){ + ClassPath path = getModelUnit().getSourcePath(); + FileObject[] roots = path.getRoots(); + assert roots.length == 1; + myBeansModel= new TestBeansModelImpl( roots[0]); + } + } + + public MetadataModel createTestModel( ){ + return MetadataModelFactory.createMetadataModel( this ); + } + + @Override + public BeansModel getBeansModel() { + return myBeansModel; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.WebBeansModelImplementation#getHelper() + */ + @Override + protected AnnotationModelHelper getHelper() { + return super.getHelper(); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.api.model.AbstractModelImplementation#getProvider() + */ + @Override + protected TestWebBeansModelProviderImpl getProvider() { + return myProvider; + } + + protected boolean isFull(){ + return isFullModel; + } + + private TestWebBeansModelProviderImpl myProvider; + private boolean isFullModel; + private TestBeansModelImpl myBeansModel; +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/TestWebBeansModelProviderImpl.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/TestWebBeansModelProviderImpl.java new file mode 100644 index 000000000000..1e1fb43beb6c --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/TestWebBeansModelProviderImpl.java @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.util.concurrent.atomic.AtomicBoolean; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.jakarta.web.beans.api.model.DependencyInjectionResult; +import org.netbeans.modules.jakarta.web.beans.impl.model.ResultLookupStrategy; +import org.netbeans.modules.jakarta.web.beans.impl.model.SingleResultLookupStrategy; +import org.netbeans.modules.jakarta.web.beans.impl.model.WebBeansModelImplementation; +import org.netbeans.modules.jakarta.web.beans.impl.model.WebBeansModelProviderImpl; + + + +/** + * @author ads + * + */ +public class TestWebBeansModelProviderImpl extends WebBeansModelProviderImpl { + + private static final ResultLookupStrategy SINGLE_STRATEGY = new TestResultStrategy(null); + + TestWebBeansModelProviderImpl(TestWebBeansModelImpl testWebBeansModelImpl ) + { + super( testWebBeansModelImpl ); + } + + @Override + protected TestWebBeansModelImpl getModel() { + return (TestWebBeansModelImpl)super.getModel(); + } + + @Override + protected DependencyInjectionResult findParameterInjectable( VariableElement element, + DeclaredType parentType, ResultLookupStrategy strategy, AtomicBoolean cancel ) + { + return super.findParameterInjectable(element, parentType, strategy, cancel); + } + + @Override + protected DependencyInjectionResult doFindVariableInjectable( VariableElement element, + TypeMirror elementType, boolean injectRequired, AtomicBoolean cancel ) + { + return super.doFindVariableInjectable(element, elementType, + injectRequired, cancel); + } + + @Override + protected DependencyInjectionResult findVariableInjectable( VariableElement element, + DeclaredType parentType, ResultLookupStrategy strategy, AtomicBoolean cancel ) + { + return super.findVariableInjectable(element, parentType, strategy, cancel ); + } + + protected DependencyInjectionResult findParameterInjectable( VariableElement element, + DeclaredType parentType, AtomicBoolean cancel ) + { + return findParameterInjectable(element, parentType, SINGLE_STRATEGY, cancel); + } + + protected DependencyInjectionResult findVariableInjectable( VariableElement element, + DeclaredType parentType, AtomicBoolean cancel ) + { + return findVariableInjectable(element, parentType, SINGLE_STRATEGY, cancel); + } + +} + +class TestResultStrategy extends SingleResultLookupStrategy implements ResultLookupStrategy { + + TestResultStrategy( ResultLookupStrategy delegate ){ + myStartegy = delegate; + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.SingleResultLookupStrategy#getResult(org.netbeans.modules.jakarta.web.beans.impl.model.WebBeansModelImplementation, org.netbeans.modules.jakarta.web.beans.api.model.Result) + */ + @Override + public DependencyInjectionResult getResult( WebBeansModelImplementation model, DependencyInjectionResult result, AtomicBoolean cancel ){ + if ( myStartegy != null && ((TestWebBeansModelImpl)model).isFull() ){ + return myStartegy.getResult(model,result, cancel); + } + else { + filterBeans(result , model, cancel ); + return result; + } + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.SingleResultLookupStrategy#getType(org.netbeans.modules.jakarta.web.beans.impl.model.WebBeansModelImplementation, javax.lang.model.type.DeclaredType, javax.lang.model.element.VariableElement) + */ + @Override + public TypeMirror getType( WebBeansModelImplementation model, + DeclaredType parent, VariableElement element ) + { + if ( myStartegy != null ){ + return myStartegy.getType(model, parent, element); + } + return super.getType(model, parent, element); + } + + /* (non-Javadoc) + * @see org.netbeans.modules.jakarta.web.beans.impl.model.SingleResultLookupStrategy#getType(org.netbeans.modules.jakarta.web.beans.impl.model.WebBeansModelImplementation, javax.lang.model.type.TypeMirror) + */ + @Override + public TypeMirror getType( WebBeansModelImplementation model, + TypeMirror typeMirror ) + { + if ( myStartegy != null ){ + return myStartegy.getType(model, typeMirror); + } + return super.getType(model, typeMirror); + } + + private ResultLookupStrategy myStartegy ; +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/TypedTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/TypedTest.java new file mode 100644 index 000000000000..18cf3e905549 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/model/TypedTest.java @@ -0,0 +1,351 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.model; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelException; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; + + +/** + * @author ads + * + */ +public class TypedTest extends CommonTestCase { + + public TypedTest( String testName ) { + super(testName); + } + + public void testCommon() throws MetadataModelException, IOException, + InterruptedException + { + createQualifier("Binding"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "import jakarta.enterprise.inject.Typed; "+ + "@Binding "+ + "@Typed( {Iface3.class} ) "+ + "public class One implements Iface3 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "import jakarta.enterprise.inject.Typed; "+ + "@Typed( {Iface2.class} ) "+ + "@Binding "+ + "public class Two extends One implements Iface2 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.Typed; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "@Typed( { Iface3.class} ) "+ + "@Binding "+ + "public class Three extends Two {" + + " @Produces @Typed({One.class}) @Binding Two productionFieldA=null; " + + " @Produces @Typed({Object[].class}) @Binding String productionFieldB[]=null; " + + " @Produces @Typed({Two[].class}) @Binding Three productionFieldC[]=null; " + + " @Produces @Typed({Two.class}) @Binding Two productionMethodA() " + + "{return null; } " + + " @Produces @Typed({Integer.class}) @Binding Integer productionMethodB() " + + "{return null; } " + + " @Produces @Typed({Number.class}) @Binding Byte productionMethodC() " + + "{return null; } " + + "}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface1.java", + "package foo; " + + "@Binding "+ + "public interface Iface1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface2.java", + "package foo; " + + "import jakarta.enterprise.inject.Typed; "+ + "@Typed( {Iface1.class , Iface2.class} ) "+ + "@Binding "+ + "public interface Iface2 extends Iface1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Iface3.java", + "package foo; " + + "@Binding "+ + "public interface Iface3 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass.java", + "package foo; " + + "import jakarta.inject.*; "+ + "public class TestClass { " + + " @Inject @foo.Binding Iface1 myFieldA; "+ + " @Inject @foo.Binding One myFieldB; "+ + " @Inject @foo.Binding String[] myFieldC; "+ + " @Inject @foo.Binding Two[] myFieldD; "+ + " @Inject @foo.Binding Two myFieldE; "+ + " @Inject @foo.Binding int myFieldF; "+ + " @Inject @foo.Binding Number myFieldG; "+ + "} "); + + inform("start restriction types test"); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction( new MetadataModelAction(){ + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType( "foo.TestClass" ); + Element clazz = ((DeclaredType)mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = + new ArrayList( children.size()); + for (Element element : children) { + if ( element instanceof VariableElement ){ + injectionPoints.add( (VariableElement)element); + } + } + + Set names = new HashSet(); + for( VariableElement element : injectionPoints ){ + names.add( element.getSimpleName().toString() ); + if ( element.getSimpleName().contentEquals("myFieldA")){ + assertFindVariableResultInjectables((VariableElement)element, + provider, "foo.Iface2", "foo.Iface1"); + assertFindVariableResultProductions((VariableElement)element, provider); + } + else if ( element.getSimpleName().contentEquals("myFieldB")){ + assertFindVariableResultInjectables((VariableElement)element, + provider); + assertFindVariableResultProductionsVar((VariableElement)element, + provider, "productionFieldA"); + } + else if ( element.getSimpleName().contentEquals("myFieldC")){ + assertFindVariableResultInjectables((VariableElement)element, + provider); + assertFindVariableResultProductionsVar((VariableElement)element, provider); + } + else if ( element.getSimpleName().contentEquals("myFieldD")){ + assertFindVariableResultInjectables((VariableElement)element, + provider); + assertFindVariableResultProductionsVar((VariableElement)element, + provider, "productionFieldC"); + } + else if ( element.getSimpleName().contentEquals("myFieldE")){ + assertFindVariableResultInjectables((VariableElement)element, + provider); + assertFindVariableResultProductions((VariableElement)element, + provider, "productionMethodA"); + } + else if ( element.getSimpleName().contentEquals("myFieldF")){ + assertFindVariableResultInjectables((VariableElement)element, + provider); + assertFindVariableResultProductions((VariableElement)element, + provider, "productionMethodB"); + } + else if ( element.getSimpleName().contentEquals("myFieldG")){ + assertFindVariableResultInjectables((VariableElement)element, + provider); + assertFindVariableResultProductions((VariableElement)element, + provider, "productionMethodC"); + } + } + assert names.contains("myFieldA"); + assert names.contains("myFieldB"); + assert names.contains("myFieldC"); + assert names.contains("myFieldD"); + assert names.contains("myFieldE"); + assert names.contains("myFieldF"); + assert names.contains("myFieldG"); + return null; + } + + }); + } + + public void testRawParametrized() throws MetadataModelException, + IOException, InterruptedException + { + createQualifier("Binding1"); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic.java", + "package foo; " + + "import jakarta.enterprise.inject.Typed; "+ + "@Binding1 "+ + "@Typed( {Object.class} ) "+ + "public class Generic {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic1.java", + "package foo; " + + "import jakarta.enterprise.inject.Typed; "+ + "@Binding1 "+ + "@Typed( {Generic.class} ) "+ + "public class Generic1 extends Generic {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One.java", + "package foo; " + + "public class One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two.java", + "package foo; " + + "public class Two extends One {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/One1.java", + "package foo; " + + "public class One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Two1.java", + "package foo; " + + "public class Two1 extends One1 {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic2.java", + "package foo; " + + "import jakarta.enterprise.inject.Typed; "+ + "@Binding1 "+ + "@Typed( {Generic.class} ) "+ + "public class Generic2 extends Generic {}" ); + + TestUtilities.copyStringToFileObject(srcFO, "foo/Generic3.java", + "package foo; " + + "import jakarta.enterprise.inject.Typed; "+ + "@Binding1 "+ + "@Typed( {Generic.class} ) "+ + "public class Generic3 extends Generic {}" ); + + + TestUtilities.copyStringToFileObject(srcFO, "foo/Three.java", + "package foo; " + + "import jakarta.enterprise.inject.Typed; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.util.*; "+ + "@Binding1 "+ + "public class Three {" + + " @Produces @Typed({Collection.class}) @Binding1 List productionFieldA=null; " + + " @Produces @Typed({List.class}) @Binding1 LinkedList productionFieldB=null; " + + " @Produces @Typed({Set.class}) @Binding1 HashSet productionMethodA() " + + "{return null; } " + + " @Produces @Typed({AbstractList.class}) @Binding1 ArrayList productionMethodB() " + + "{return null; } " + + "}" ); + + + TestUtilities.copyStringToFileObject(srcFO, "foo/TestClass1.java", + "package foo; " + + "import jakarta.inject.*; "+ + "import java.util.*; "+ + "public class TestClass1 { " + + " @Inject @foo.Binding1 Generic myFieldA; "+ + " @Inject @foo.Binding1 Generic myFieldB; "+ + " @Inject @foo.Binding1 Generic myFieldC; "+ + " @Inject @foo.Binding1 List myFieldD; "+ + " @Inject @foo.Binding1 Set myFieldE; "+ + " @Inject @foo.Binding1 AbstractList myFieldF; "+ + "} "); + + inform("start restriction types for generic case test"); + + TestWebBeansModelImpl modelImpl = createModelImpl(); + final TestWebBeansModelProviderImpl provider = modelImpl.getProvider(); + MetadataModel testModel = modelImpl.createTestModel(); + + testModel.runReadAction(new MetadataModelAction() { + + public Void run( WebBeansModel model ) throws Exception { + TypeMirror mirror = model.resolveType("foo.TestClass1"); + Element clazz = ((DeclaredType) mirror).asElement(); + List children = clazz.getEnclosedElements(); + List injectionPoints = new ArrayList( + children.size()); + for (Element element : children) { + if (element instanceof VariableElement) { + injectionPoints.add((VariableElement) element); + } + } + + Set names = new HashSet(); + for (VariableElement element : injectionPoints) { + names.add(element.getSimpleName().toString()); + if (element.getSimpleName().contentEquals("myFieldA")) { + assertFindVariableResultInjectables( + (VariableElement) element, provider,"foo.Generic1"); + assertFindVariableResultProductions( + (VariableElement) element, provider); + } + else if (element.getSimpleName().contentEquals("myFieldB")) + { + assertFindVariableResultInjectables( + (VariableElement) element, provider,"foo.Generic1", + "foo.Generic2"); + assertFindVariableResultProductions( + (VariableElement) element, provider); + } + else if (element.getSimpleName().contentEquals("myFieldC")) + { + assertFindVariableResultInjectables( + (VariableElement) element, provider,"foo.Generic1"); + assertFindVariableResultProductions( + (VariableElement) element, provider); + } + else if (element.getSimpleName().contentEquals("myFieldD")) + { + assertFindVariableResultInjectables( + (VariableElement) element, provider); + assertFindVariableResultProductionsVar( + (VariableElement) element, provider,"productionFieldB"); + } + else if (element.getSimpleName().contentEquals("myFieldE")) + { + assertFindVariableResultInjectables( + (VariableElement) element, provider); + assertFindVariableResultProductions( + (VariableElement) element, provider,"productionMethodA"); + } + else if (element.getSimpleName().contentEquals("myFieldF")) + { + assertFindVariableResultInjectables( + (VariableElement) element, provider); + assertFindVariableResultProductions( + (VariableElement) element, provider,"productionMethodB"); + } + } + assert names.contains("myFieldA"); + assert names.contains("myFieldB"); + assert names.contains("myFieldC"); + assert names.contains("myFieldD"); + assert names.contains("myFieldE"); + assert names.contains("myFieldF"); + return null; + } + + }); + } +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/testutilities/CdiTestUtilities.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/testutilities/CdiTestUtilities.java new file mode 100644 index 000000000000..1030490cc099 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/testutilities/CdiTestUtilities.java @@ -0,0 +1,525 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.testutilities; + +import java.io.IOException; + +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; +import org.netbeans.modules.j2ee.metadata.model.support.TestUtilities; +import org.netbeans.modules.jakarta.web.beans.api.model.ModelUnit; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModelFactory; +import org.openide.filesystems.FileObject; + + +/** + * @author ads + * + */ +public class CdiTestUtilities { + + public CdiTestUtilities( FileObject fileObject ){ + mySourceRoot = fileObject; + } + + public void clearRoot() throws IOException { + FileObject[] children = mySourceRoot.getChildren(); + for (FileObject fileObject : children) { + fileObject.delete(); + } + } + + public MetadataModel createBeansModel() throws IOException, InterruptedException { + ModelUnit modelUnit = ModelUnit.create( + ClassPath.getClassPath(mySourceRoot, ClassPath.BOOT), + ClassPath.getClassPath(mySourceRoot, ClassPath.COMPILE), + ClassPath.getClassPath(mySourceRoot, ClassPath.SOURCE), null); + return WebBeansModelFactory.createMetaModel(modelUnit); + } + + public void createQualifier(String name ) throws IOException{ + TestUtilities.copyStringToFileObject(mySourceRoot, "foo/"+name+".java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface "+name+" {} "); + } + + public void createInterceptorBinding(String name ) throws IOException{ + TestUtilities.copyStringToFileObject(mySourceRoot, "foo/"+name+".java", + "package foo; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import jakarta.enterprise.inject.*; "+ + "import jakarta.inject.*; "+ + "import java.lang.annotation.*; "+ + "import jakarta.interceptor.*; "+ + "@InterceptorBinding " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, TYPE}) "+ + "public @interface "+name+" {} "); + } + + public void initEnterprise() throws IOException{ + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/ejb/Singleton.java", + "package jakarta.ejb; " + + "import static java.lang.annotation.ElementType; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({ElementType.TYPE}) "+ + "public @interface Singleton {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/ejb/Stateless.java", + "package jakarta.ejb; " + + "import static java.lang.annotation.ElementType; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({ElementType.TYPE}) "+ + "public @interface Stateless {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/ejb/Stateful.java", + "package jakarta.ejb; " + + "import static java.lang.annotation.ElementType; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({ElementType.TYPE}) "+ + "public @interface Stateful {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/ejb/PostActivate.java", + "package jakarta.ejb; " + + "import static java.lang.annotation.ElementType; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({ElementType.METHOD}) "+ + "public @interface PostActivate {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/ejb/PrePassivate.java", + "package jakarta.ejb; " + + "import static java.lang.annotation.ElementType; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({ElementType.METHOD}) "+ + "public @interface PrePassivate {}"); + } + + public void initAnnotations() throws IOException{ + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/inject/Qualifier.java", + "package jakarta.inject; " + + "import static java.lang.annotation.ElementType.ANNOTATION_TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({ElementType.ANNOTATION_TYPE}) "+ + "public @interface Qualifier {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/inject/Named.java", + "package jakarta.inject; " + + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Qualifier "+ + "public @interface Named { " + + " String value(); "+ + "}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/inject/Inject.java", + "package jakarta.inject; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.CONSTRUCTOR; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, CONSTRUCTOR}) "+ + "public @interface Inject {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/inject/Any.java", + "package jakarta.enterprise.inject; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "import jakarta.inject.Qualifier; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Any {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/inject/New.java", + "package jakarta.enterprise.inject; " + + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "import jakarta.inject.Qualifier; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({FIELD, PARAMETER}) "+ + "public @interface New { " + + " Class value() ; "+ + "}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/inject/Default.java", + "package jakarta.enterprise.inject; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import jakarta.inject.Qualifier; "+ + "@Qualifier " + + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, PARAMETER, TYPE}) "+ + "public @interface Default {} "); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/inject/Produces.java", + "package jakarta.enterprise.inject; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD }) "+ + "public @interface Produces {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/util/Nonbinding.java", + "package jakarta.enterprise.util; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({METHOD }) "+ + "public @interface Nonbinding {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/event/Observes.java", + "package jakarta.enterprise.event; " + + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({PARAMETER}) "+ + "public @interface Observes {}"); + + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/inject/Disposes.java", + "package jakarta.enterprise.inject; " + + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({PARAMETER}) "+ + "public @interface Disposes {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/inject/Specializes.java", + "package jakarta.enterprise.inject; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({TYPE,METHOD }) "+ + "public @interface Specializes {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/inject/Alternative.java", + "package jakarta.enterprise.inject; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "public @interface Alternative {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/inject/Stereotype.java", + "package jakarta.enterprise.inject; " + + "import static java.lang.annotation.ElementType.ANNOTATION_TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({ANNOTATION_TYPE}) "+ + "public @interface Stereotype {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/context/NormalScope.java", + "package jakarta.enterprise.context; " + + "import static java.lang.annotation.ElementType.ANNOTATION_TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({ANNOTATION_TYPE}) "+ + "public @interface NormalScope {" + + " boolean passivating() default faslse ; "+ + "}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/inject/Scope.java", + "package jakarta.inject; " + + "import static java.lang.annotation.ElementType.ANNOTATION_TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({ANNOTATION_TYPE}) "+ + "public @interface Scope {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/context/ApplicationScoped.java", + "package jakarta.enterprise.context; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@NormalScope "+ + "@Inherited "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "public @interface ApplicationScoped {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/context/ConversationScoped.java", + "package jakarta.enterprise.context; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@NormalScope(passivating=true) "+ + "@Inherited "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "public @interface ConversationScoped {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/context/Dependent.java", + "package jakarta.enterprise.context; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "import jakarta.inject.Scope; "+ + "@Retention(RUNTIME) "+ + "@Scope "+ + "@Inherited "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "public @interface Dependent {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/context/RequestScoped.java", + "package jakarta.enterprise.context; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@NormalScope "+ + "@Inherited "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "public @interface RequestScoped {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/context/SessionScoped.java", + "package jakarta.enterprise.context; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@NormalScope(passivating=true) "+ + "@Inherited "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "public @interface SessionScoped {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/inject/Typed.java", + "package jakarta.enterprise.inject; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({METHOD, FIELD, TYPE}) "+ + "public @interface Typed {" + + " Class[] value() ; "+ + "}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/event/Event.java", + "package jakarta.enterprise.event; " + + "public interface Event {" + + " void fire( T event ); "+ + "}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/decorator/Delegate.java", + "package jakarta.decorator; " + + "import static java.lang.annotation.ElementType.FIELD; "+ + "import static java.lang.annotation.ElementType.PARAMETER; "+ + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({FIELD, PARAMETER}) "+ + "public @interface Delegate {" + + "}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/decorator/Decorator.java", + "package jakarta.decorator; " + + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({TYPE}) "+ + "@jakarta.enterprise.inject.Stereotype "+ + "public @interface Decorator {" + + "}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/inject/Instance.java", + "package jakarta.enterprise.inject; " + + "public interface Instance extends java.lang.Iterable {" + + " void fire( T event ); "+ + "}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/inject/spi/Extension.java", + "package jakarta.enterprise.inject.spi; " + + "public interface Extension {}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/interceptor/InterceptorBinding.java", + "package jakarta.interceptor; " + + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import static java.lang.annotation.ElementType.ANNOTATION_TYPE; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({ANNOTATION_TYPE}) "+ + "public @interface InterceptorBinding {" + + "}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/interceptor/Interceptor.java", + "package jakarta.interceptor; " + + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({TYPE}) "+ + "public @interface Interceptor {" + + "}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/interceptor/Interceptors.java", + "package jakarta.interceptor; " + + "import static java.lang.annotation.RetentionPolicy.RUNTIME; "+ + "import static java.lang.annotation.ElementType.TYPE; "+ + "import static java.lang.annotation.ElementType.METHOD; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({TYPE,METHOD}) "+ + "public @interface Interceptors {" + + " Class[] value(); "+ + "}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/ejb/Singleton.java", + "package jakarta.ejb; " + + "import static java.lang.annotation.ElementType.TYPE; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({TYPE}) "+ + "public @interface Singleton {" + + " String name() default \"\"; "+ + " String description() default \"\"; "+ + " String mappedName() default \"\"; "+ + "}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/ejb/Stateful.java", + "package jakarta.ejb; " + + "import static java.lang.annotation.ElementType.TYPE; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({TYPE}) "+ + "public @interface Stateful {" + + " String name() default \"\"; "+ + " String description() default \"\"; "+ + " String mappedName() default \"\"; "+ + "}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/ejb/PostActivate.java", + "package jakarta.ejb; " + + "import static java.lang.annotation.ElementType.METHOD; "+ + "import java.lang.annotation.*; "+ + "import java.lang.annotation.RetentionPolicy; "+ + "@Retention(RUNTIME) "+ + "@Target({METHOD}) "+ + "public @interface PostActivate {" + + "}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/inject/spi/InjectionPoint.java", + "package jakarta.enterprise.inject.spi; " + + "public interface InjectionPoint {" + + "}"); + + TestUtilities.copyStringToFileObject(mySourceRoot, "javax/enterprise/context/spi/Context.java", + "package jakarta.enterprise.context.spi; " + + "public interface Context {" + + "}"); + } + + private FileObject mySourceRoot; +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/BeansComponentTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/BeansComponentTest.java new file mode 100644 index 000000000000..5f86c4348bb9 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/BeansComponentTest.java @@ -0,0 +1,180 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xdm.model; + +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.netbeans.junit.NbTestCase; +import org.netbeans.modules.jakarta.web.beans.xml.AlternativeElement; +import org.netbeans.modules.jakarta.web.beans.xml.Alternatives; +import org.netbeans.modules.jakarta.web.beans.xml.BeanClass; +import org.netbeans.modules.jakarta.web.beans.xml.Beans; +import org.netbeans.modules.jakarta.web.beans.xml.BeansElement; +import org.netbeans.modules.jakarta.web.beans.xml.Decorators; +import org.netbeans.modules.jakarta.web.beans.xml.Interceptors; +import org.netbeans.modules.jakarta.web.beans.xml.Stereotype; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansModel; + + +/** + * @author ads + * + */ +public class BeansComponentTest extends NbTestCase { + + public BeansComponentTest( String name ) { + super(name); + } + + @Override + protected Level logLevel() { + return Level.INFO; + } + + protected void setUp() throws Exception { + Logger.getLogger(WebBeansModel.class.getName()).setLevel(Level.FINEST); + } + + public void testEmpty() throws Exception { + WebBeansModel model = Util.loadRegistryModel("empty-beans.xml"); + model.sync(); + + Beans beans = model.getBeans(); + List elements = beans.getElements(); + assertEquals(0, elements.size()); + assertEquals(0, beans.getChildren().size()); + } + + public void testBeans() throws Exception{ + WebBeansModel model = Util.loadRegistryModel("beans.xml"); + model.sync(); + + Beans beans = model.getBeans(); + List elements = beans.getElements(); + + assertEquals(6, elements.size()); + + BeansElement beansElement = elements.get(0); + assertTrue( beansElement instanceof Interceptors ); + beansElement = elements.get(1); + assertTrue( beansElement instanceof Interceptors ); + + beansElement = elements.get(2); + assertTrue( beansElement instanceof Decorators ); + beansElement = elements.get(4); + assertTrue( beansElement instanceof Decorators ); + + beansElement = elements.get(3); + assertTrue( beansElement instanceof Alternatives ); + beansElement = elements.get(5); + assertTrue( beansElement instanceof Alternatives ); + } + + public void testInterceptors() throws Exception{ + WebBeansModel model = Util.loadRegistryModel("beans.xml"); + model.sync(); + + Beans beans = model.getBeans(); + List elements = beans.getElements(); + + BeansElement beansElement = elements.get(0); + assertTrue( beansElement instanceof Interceptors ); + + Interceptors interceptors = (Interceptors)beansElement; + assertEquals( 0, interceptors.getChildren().size() ); + + beansElement = elements.get(1); + assertTrue( beansElement instanceof Interceptors ); + + interceptors = (Interceptors)beansElement; + assertEquals( 1, interceptors.getChildren().size() ); + + List beansClasses = interceptors.getBeansClasses(); + assertEquals(1, beansClasses.size()); + String beanClass = beansClasses.get(0 ).getBeanClass(); + assertEquals("Class1", beanClass); + } + + + public void testDecorators() throws Exception{ + WebBeansModel model = Util.loadRegistryModel("beans.xml"); + model.sync(); + + Beans beans = model.getBeans(); + List elements = beans.getElements(); + + BeansElement beansElement = elements.get(4); + assertTrue( beansElement instanceof Decorators ); + + Decorators decorators = (Decorators)beansElement; + assertEquals( 0, decorators.getChildren().size() ); + + beansElement = elements.get(2); + assertTrue( beansElement instanceof Decorators ); + + decorators = (Decorators)beansElement; + assertEquals( 1, decorators.getChildren().size() ); + + List beansClasses = decorators.getBeansClasses(); + assertEquals(1, beansClasses.size()); + String beanClass = beansClasses.get(0 ).getBeanClass(); + assertEquals("Class2", beanClass); + } + + public void testAlternatives() throws Exception{ + WebBeansModel model = Util.loadRegistryModel("beans.xml"); + model.sync(); + + Beans beans = model.getBeans(); + List elements = beans.getElements(); + + BeansElement beansElement = elements.get(3); + assertTrue( beansElement instanceof Alternatives ); + + Alternatives alternatives = (Alternatives)beansElement; + assertEquals( 0, alternatives.getChildren().size() ); + + beansElement = elements.get(5); + assertTrue( beansElement instanceof Alternatives ); + + alternatives = (Alternatives)beansElement; + + List alternativeElements = alternatives.getElements(); + assertEquals(2, alternativeElements.size()); + AlternativeElement element = alternativeElements.get(0 ); + + assertTrue( element instanceof BeanClass ); + String beanClass = ((BeanClass)element).getBeanClass(); + assertEquals("Class3", beanClass ); + + element = alternativeElements.get(1 ); + assertTrue( element instanceof Stereotype ); + + String stereotype = ((Stereotype)element).getStereotype(); + assertEquals("Stereotype1", stereotype); + } + + /* + * TODO : modification OM tests. + * ads : At this moment OM is used only for reading . So there is no + * need in modification . As consequence modification tests are not written. + */ +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/SyncUpdateTest.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/SyncUpdateTest.java new file mode 100644 index 000000000000..428c758e5a06 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/SyncUpdateTest.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.jakarta.web.beans.xdm.model; + +import java.util.List; + +import org.netbeans.junit.NbTestCase; +import org.netbeans.modules.jakarta.web.beans.xml.AlternativeElement; +import org.netbeans.modules.jakarta.web.beans.xml.Alternatives; +import org.netbeans.modules.jakarta.web.beans.xml.BeanClass; +import org.netbeans.modules.jakarta.web.beans.xml.BeansElement; +import org.netbeans.modules.jakarta.web.beans.xml.Decorators; +import org.netbeans.modules.jakarta.web.beans.xml.Interceptors; +import org.netbeans.modules.jakarta.web.beans.xml.Stereotype; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansModel; + + +/** + * @author ads + * + */ +public class SyncUpdateTest extends NbTestCase { + + public SyncUpdateTest( String name ) { + super(name); + } + + public void testSyncBeansElements() throws Exception{ + WebBeansModel model = Util.loadRegistryModel("beans-orig.xml"); + + Util.setDocumentContentTo(model, "beans.xml"); + + List elements = model.getBeans().getElements(); + assertEquals( 6 , elements.size()); + + BeansElement beansElement = elements.get(1); + assertTrue( beansElement instanceof Interceptors ); + + beansElement = elements.get(4); + assertTrue( beansElement instanceof Decorators ); + + beansElement = elements.get(5); + assertTrue( beansElement instanceof Alternatives ); + + List alternativeElements = ((Alternatives)beansElement). + getElements(); + assertEquals(2, alternativeElements.size()); + AlternativeElement element = alternativeElements.get(0 ); + + assertTrue( element instanceof BeanClass ); + String beanClass = ((BeanClass)element).getBeanClass(); + assertEquals("Class3", beanClass ); + + element = alternativeElements.get(1 ); + assertTrue( element instanceof Stereotype ); + + String stereotype = ((Stereotype)element).getStereotype(); + assertEquals("Stereotype1", stereotype); + } + + public void testAlternatives() throws Exception{ + WebBeansModel model = Util.loadRegistryModel("alternatives-beans-orig.xml"); + + Util.setDocumentContentTo(model, "alternatives-beans.xml"); + + List elements = model.getBeans().getElements(); + assertEquals( 1 , elements.size()); + + Alternatives alternatives = (Alternatives)elements.get(0); + List alternativeElements = alternatives.getElements(); + assertEquals(5, alternativeElements.size()); + + AlternativeElement alternativeElement = alternativeElements.get(2); + assertTrue( alternativeElement instanceof BeanClass ); + String beanClass = ((BeanClass)alternativeElement).getBeanClass(); + assertEquals( "Class2", beanClass); + + alternativeElement = alternativeElements.get(3); + assertTrue( alternativeElement instanceof BeanClass ); + beanClass = ((BeanClass)alternativeElement).getBeanClass(); + assertEquals( "Class3", beanClass); + + alternativeElement = alternativeElements.get(4); + assertTrue( alternativeElement instanceof Stereotype ); + String stereotype = ((Stereotype)alternativeElement).getStereotype(); + assertEquals( "Stereotype2", stereotype); + } +} diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/TestCatalogModel.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/TestCatalogModel.java new file mode 100644 index 000000000000..6f0937da21a4 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/TestCatalogModel.java @@ -0,0 +1,178 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.jakarta.web.beans.xdm.model; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import javax.swing.text.Document; +import org.netbeans.modules.xml.retriever.catalog.impl.CatalogFileWrapperDOMImpl; +import org.netbeans.modules.xml.retriever.catalog.impl.CatalogWriteModelImpl; +import org.netbeans.modules.xml.xam.locator.CatalogModel; +import org.netbeans.modules.xml.xam.locator.CatalogModelException; +import org.netbeans.modules.xml.xam.ModelSource; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.loaders.DataObject; +import org.openide.loaders.DataObjectNotFoundException; +import org.openide.util.Lookup; +import org.openide.util.lookup.Lookups; + +/** + * + * @author girix + */ + +public class TestCatalogModel extends CatalogWriteModelImpl{ + private TestCatalogModel(File file) throws IOException{ + super(file); + } + + static TestCatalogModel singletonCatMod = null; + public static TestCatalogModel getDefault(){ + if (singletonCatMod == null){ + CatalogFileWrapperDOMImpl.TEST_ENVIRONMENT = true; + try { + singletonCatMod = new TestCatalogModel(Util.getTempDir("schematest/catalog")); + FileObject catalogFO = singletonCatMod.getCatalogFileObject(); + File catFile = FileUtil.toFile(catalogFO); + catFile.deleteOnExit(); + initCatalogFile(); + } catch (Exception ex) { + ex.printStackTrace(); + return null; + } + } + return singletonCatMod; + } + + + /** + * This method could be overridden by the Unit testcase to return a special + * ModelSource object for a FileObject with custom impl of classes added to the lookup. + * This is optional if both getDocument(FO) and createCatalogModel(FO) are overridden. + */ + protected ModelSource createModelSource(final FileObject thisFileObj, boolean editable) throws CatalogModelException{ + assert thisFileObj != null : "Null file object."; + final CatalogModel catalogModel = createCatalogModel(thisFileObj); + final DataObject dobj; + try { + dobj = DataObject.find(thisFileObj); + } catch (DataObjectNotFoundException ex) { + throw new CatalogModelException(ex); + } + Lookup proxyLookup = Lookups.proxy( + new Lookup.Provider() { + public Lookup getLookup() { + Document document = null; + document = getDocument(thisFileObj); + return Lookups.fixed(new Object[] { + FileUtil.toFile(thisFileObj), + thisFileObj, + document, + dobj, + catalogModel + }); + } + } + ); + return new ModelSource(proxyLookup, editable); + } + + private Document getDocument(FileObject fo){ + Document result = null; + if (documentPooling) { + result = documentPool().get(fo); + } + if (result != null) return result; + try { + + File file = FileUtil.toFile(fo); + byte[] buffer; + try (FileInputStream fis = new FileInputStream(file)) { + buffer = new byte[fis.available()]; + result = new org.netbeans.editor.BaseDocument( + org.netbeans.modules.xml.text.syntax.XMLKit.class, false); + result.remove(0, result.getLength()); + fis.read(buffer); + } + String str = new String(buffer); + result.insertString(0,str,null); + + } catch (Exception dObjEx) { + return null; + } + if (documentPooling) { + documentPool().put(fo, result); + } + return result; + } + + protected CatalogModel createCatalogModel(FileObject fo) throws CatalogModelException{ + return getDefault(); + } + + public ModelSource createTestModelSource(FileObject fo, boolean editable) throws CatalogModelException{ + final DataObject dobj; + final CatalogModel catalogModel = createCatalogModel(fo); + try { + dobj = DataObject.find(fo); + } catch (DataObjectNotFoundException ex) { + throw new CatalogModelException(ex); + } + Lookup lookup = Lookups.proxy(new Lookup.Provider() { + public Lookup getLookup() { + return Lookups.fixed(new Object[] { + dobj.getPrimaryFile(), + getDocument(dobj.getPrimaryFile()), + dobj, + catalogModel + }); + } + } ); + return new ModelSource(lookup, editable); + } + + private static void initCatalogFile() throws Exception { + } + + private Map fileToDocumentMap; + private Map documentPool() { + if (fileToDocumentMap == null) { + fileToDocumentMap = new HashMap(); + } + return fileToDocumentMap; + } + private boolean documentPooling = true; + + public void setDocumentPooling(boolean v) { + documentPooling = v; + if (! documentPooling) { + clearDocumentPool(); + } + } + + public void clearDocumentPool() { + fileToDocumentMap = null; + } +} + diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/Util.java b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/Util.java new file mode 100644 index 000000000000..230206175e58 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/Util.java @@ -0,0 +1,203 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.netbeans.modules.jakarta.web.beans.xdm.model; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.net.URI; +import javax.swing.text.Document; + +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansModel; +import org.netbeans.modules.jakarta.web.beans.xml.WebBeansModelFactory; +import org.netbeans.modules.xml.xam.ModelSource; +import org.netbeans.modules.xml.xam.dom.AbstractDocumentModel; +import org.netbeans.modules.xml.xam.dom.DocumentModel; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * + * @author nn136682 + */ +public class Util { + static { + //JEditorPane.registerEditorKitForContentType(SchemaDataLoader.MIME_TYPE, XMLKit.class.getName()); + registerXMLKit(); + } + + public static void registerXMLKit() { + String[] path = new String[] { "Editors", "text", "x-xml" }; + FileObject target = FileUtil.getConfigRoot(); + try { + for (int i=0; i + + + + Class1 + Stereotype1 + + diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/alternatives-beans.xml b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/alternatives-beans.xml new file mode 100644 index 000000000000..3778b81cc4f0 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/alternatives-beans.xml @@ -0,0 +1,30 @@ + + + + + Class1 + Stereotype1 + Class2 + Class3 + Stereotype2 + + diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/beans-orig.xml b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/beans-orig.xml new file mode 100644 index 000000000000..ac3f263d66b2 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/beans-orig.xml @@ -0,0 +1,28 @@ + + + + + + Class2 + + + diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/beans.xml b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/beans.xml new file mode 100644 index 000000000000..5284136e6091 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/beans.xml @@ -0,0 +1,36 @@ + + + + + + Class1 + + + Class2 + + + + + Class3 + Stereotype1 + + diff --git a/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/empty-beans.xml b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/empty-beans.xml new file mode 100644 index 000000000000..2de154643cd7 --- /dev/null +++ b/enterprise/jakarta.web.beans/test/unit/src/org/netbeans/modules/jakarta/web/beans/xdm/model/empty-beans.xml @@ -0,0 +1,23 @@ + + + + diff --git a/enterprise/web.beans/manifest.mf b/enterprise/web.beans/manifest.mf index 3a3b9efadf2f..ec0b801282a6 100644 --- a/enterprise/web.beans/manifest.mf +++ b/enterprise/web.beans/manifest.mf @@ -2,5 +2,5 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.modules.web.beans/2 OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/web/beans/resources/Bundle.properties OpenIDE-Module-Layer: org/netbeans/modules/web/beans/resources/layer.xml -OpenIDE-Module-Specification-Version: 2.40 +OpenIDE-Module-Specification-Version: 2.38 AutoUpdate-Show-In-Client: false diff --git a/enterprise/web.beans/nbproject/org-netbeans-modules-web-beans.sig b/enterprise/web.beans/nbproject/org-netbeans-modules-web-beans.sig index f79cf21f036a..2349855ce47d 100644 --- a/enterprise/web.beans/nbproject/org-netbeans-modules-web-beans.sig +++ b/enterprise/web.beans/nbproject/org-netbeans-modules-web-beans.sig @@ -1,5 +1,5 @@ #Signature file v4.1 -#Version 2.38 +#Version 2.37 CLSS public java.beans.FeatureDescriptor cons public init() diff --git a/enterprise/web.beans/src/org/netbeans/modules/web/beans/analysis/analyzer/AbstractDecoratorAnalyzer.java b/enterprise/web.beans/src/org/netbeans/modules/web/beans/analysis/analyzer/AbstractDecoratorAnalyzer.java index 977671f615ef..a4bc3f3f7d20 100644 --- a/enterprise/web.beans/src/org/netbeans/modules/web/beans/analysis/analyzer/AbstractDecoratorAnalyzer.java +++ b/enterprise/web.beans/src/org/netbeans/modules/web/beans/analysis/analyzer/AbstractDecoratorAnalyzer.java @@ -49,12 +49,12 @@ public abstract class AbstractDecoratorAnalyzer { protected void analyzeDecoratedBeans( DependencyInjectionResult res, - VariableElement element, T t, TypeElement decorator , + VariableElement element, T t, TypeElement decorator , WebBeansModel model, Result result ) { Set decoratedBeans = null; if ( res instanceof DependencyInjectionResult.ApplicableResult ){ - DependencyInjectionResult.ApplicableResult appResult = + DependencyInjectionResult.ApplicableResult appResult = (DependencyInjectionResult.ApplicableResult) res; decoratedBeans = appResult.getTypeElements(); } @@ -79,17 +79,17 @@ else if ( res instanceof DependencyInjectionResult.InjectableResult ){ return; } /* - * The rule : "If a decorator matches a managed bean with a non-static, + * The rule : "If a decorator matches a managed bean with a non-static, * non-private, final method, the decorator shouldn't also implement that method." - * is actually nonsense. - * Each Java class has final wait(). Decorator is also java class - * so it also has a method wait() . So it always implements + * is actually nonsense. + * Each Java class has final wait(). Decorator is also java class + * so it also has a method wait() . So it always implements * non-static, non-private final method. - * I believe one need to care about ONLY methods in decorated types : + * I believe one need to care about ONLY methods in decorated types : * all methods that are defined in interfaces ( decorated types ) * and which are implemented in the decorator and decorated bean. - * - * Here is implementation of this requirement. + * + * Here is implementation of this requirement. */ Collection decoratedTypes = DelegateFieldAnalizer .getDecoratedTypes(decorator, model.getCompilationController()); @@ -129,7 +129,7 @@ else if ( res instanceof DependencyInjectionResult.InjectableResult ){ } } } - + protected boolean checkBuiltInBeans( VariableElement element, TypeMirror elementType, WebBeansModel model, AtomicBoolean cancel ) { @@ -146,11 +146,11 @@ protected boolean checkBuiltInBeans( VariableElement element, if ( cancel.get()){ return true; } - + Element varElement = model.getCompilationController().getTypes(). asElement(elementType); if ( varElement instanceof TypeElement ){ - if ( !((TypeElement)varElement).getQualifiedName().contentEquals( + if ( !((TypeElement)varElement).getQualifiedName().contentEquals( AnnotationUtil.CONVERSATION)) { return false; @@ -159,7 +159,7 @@ protected boolean checkBuiltInBeans( VariableElement element, else { return false; } - + if ( model.hasImplicitDefaultQualifier( element ) ){ return true; } @@ -176,12 +176,12 @@ protected boolean checkBuiltInBeans( VariableElement element, } return hasOnlyDefault; } - + protected abstract void addMethodError( VariableElement element, T t, TypeElement decorated, Element decoratedMethod, WebBeansModel model, Result result ); - protected abstract void addClassError( VariableElement element , T t, + protected abstract void addClassError( VariableElement element , T t, TypeElement decoratedBean, WebBeansModel model, Result result ); - -} + +} \ No newline at end of file diff --git a/enterprise/web.beans/src/org/netbeans/modules/web/beans/analysis/analyzer/field/InjectionPointAnalyzer.java b/enterprise/web.beans/src/org/netbeans/modules/web/beans/analysis/analyzer/field/InjectionPointAnalyzer.java index ddd0a97c6d2d..626536e2c012 100644 --- a/enterprise/web.beans/src/org/netbeans/modules/web/beans/analysis/analyzer/field/InjectionPointAnalyzer.java +++ b/enterprise/web.beans/src/org/netbeans/modules/web/beans/analysis/analyzer/field/InjectionPointAnalyzer.java @@ -223,4 +223,4 @@ private void informInjectionPointDefError(InjectionPointDefinitionError exceptio { result.addError(element, model, exception.getMessage()); } -} +} \ No newline at end of file diff --git a/enterprise/web.beans/src/org/netbeans/modules/web/beans/analysis/analyzer/method/InjectionPointParameterAnalyzer.java b/enterprise/web.beans/src/org/netbeans/modules/web/beans/analysis/analyzer/method/InjectionPointParameterAnalyzer.java index 33d40c472ea8..764d298f1198 100644 --- a/enterprise/web.beans/src/org/netbeans/modules/web/beans/analysis/analyzer/method/InjectionPointParameterAnalyzer.java +++ b/enterprise/web.beans/src/org/netbeans/modules/web/beans/analysis/analyzer/method/InjectionPointParameterAnalyzer.java @@ -254,4 +254,4 @@ private void informInjectionPointDefError(InjectionPointDefinitionError exceptio result.addError(element, model, exception.getMessage()); } -} +} \ No newline at end of file diff --git a/enterprise/web.beans/src/org/netbeans/modules/web/beans/impl/model/EnableBeansFilter.java b/enterprise/web.beans/src/org/netbeans/modules/web/beans/impl/model/EnableBeansFilter.java index a8eb16764231..999dd770febb 100644 --- a/enterprise/web.beans/src/org/netbeans/modules/web/beans/impl/model/EnableBeansFilter.java +++ b/enterprise/web.beans/src/org/netbeans/modules/web/beans/impl/model/EnableBeansFilter.java @@ -594,4 +594,4 @@ private InjectableResultImpl handleEESpecificImplementations(ResultImpl result, } return null; } -} +} \ No newline at end of file diff --git a/enterprise/web.beans/src/org/netbeans/modules/web/beans/resources/BeansResolver.xml b/enterprise/web.beans/src/org/netbeans/modules/web/beans/resources/BeansResolver.xml index 9ccab439208c..4c1555f2b2b8 100644 --- a/enterprise/web.beans/src/org/netbeans/modules/web/beans/resources/BeansResolver.xml +++ b/enterprise/web.beans/src/org/netbeans/modules/web/beans/resources/BeansResolver.xml @@ -39,4 +39,3 @@ - diff --git a/enterprise/web.beans/src/org/netbeans/modules/web/beans/resources/Bundle.properties b/enterprise/web.beans/src/org/netbeans/modules/web/beans/resources/Bundle.properties index cee8b660a76e..ef5090b817ea 100644 --- a/enterprise/web.beans/src/org/netbeans/modules/web/beans/resources/Bundle.properties +++ b/enterprise/web.beans/src/org/netbeans/modules/web/beans/resources/Bundle.properties @@ -1,3 +1,4 @@ +OpenIDE-Module-Display-Category=Java EE # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information @@ -14,8 +15,9 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -OpenIDE-Module-Name=Contexts and Dependency Injection Support +OpenIDE-Module-Name=Java EE CDI Support +OpenIDE-Module-Short-Description=Context and Dependency Injection Support for Java EE Templates/CDI=Contexts and Dependency Injection Templates/CDI/beans.xml=beans.xml (CDI Configuration File) Templates/CDI/Interceptor.java=Interceptor Binding Type diff --git a/enterprise/web.beans/src/org/netbeans/modules/web/beans/resources/org-netbeans-modules-web-beans-annotations-decorated-bean.xml b/enterprise/web.beans/src/org/netbeans/modules/web/beans/resources/org-netbeans-modules-web-beans-annotations-decorated-bean.xml index e4861fe99843..bbdd353b391c 100644 --- a/enterprise/web.beans/src/org/netbeans/modules/web/beans/resources/org-netbeans-modules-web-beans-annotations-decorated-bean.xml +++ b/enterprise/web.beans/src/org/netbeans/modules/web/beans/resources/org-netbeans-modules-web-beans-annotations-decorated-bean.xml @@ -19,12 +19,12 @@ under the License. --> - - + + diff --git a/enterprise/web.beans/test/unit/src/org/netbeans/modules/web/beans/xdm/model/TestCatalogModel.java b/enterprise/web.beans/test/unit/src/org/netbeans/modules/web/beans/xdm/model/TestCatalogModel.java index 69837f4e63b9..ba96cc396fc6 100644 --- a/enterprise/web.beans/test/unit/src/org/netbeans/modules/web/beans/xdm/model/TestCatalogModel.java +++ b/enterprise/web.beans/test/unit/src/org/netbeans/modules/web/beans/xdm/model/TestCatalogModel.java @@ -107,13 +107,14 @@ private Document getDocument(FileObject fo){ try { File file = FileUtil.toFile(fo); - FileInputStream fis = new FileInputStream(file); - byte buffer[] = new byte[fis.available()]; - result = new org.netbeans.editor.BaseDocument( - org.netbeans.modules.xml.text.syntax.XMLKit.class, false); - result.remove(0, result.getLength()); - fis.read(buffer); - fis.close(); + byte[] buffer; + try (FileInputStream fis = new FileInputStream(file)) { + buffer = new byte[fis.available()]; + result = new org.netbeans.editor.BaseDocument( + org.netbeans.modules.xml.text.syntax.XMLKit.class, false); + result.remove(0, result.getLength()); + fis.read(buffer); + } String str = new String(buffer); result.insertString(0,str,null); diff --git a/enterprise/web.beans/test/unit/src/org/netbeans/modules/web/beans/xdm/model/Util.java b/enterprise/web.beans/test/unit/src/org/netbeans/modules/web/beans/xdm/model/Util.java index d3ddd487814a..b7946a406ae8 100644 --- a/enterprise/web.beans/test/unit/src/org/netbeans/modules/web/beans/xdm/model/Util.java +++ b/enterprise/web.beans/test/unit/src/org/netbeans/modules/web/beans/xdm/model/Util.java @@ -131,9 +131,9 @@ public static WebBeansModel loadRegistryModel(File schemaFile) throws Exception } public static void dumpToStream(Document doc, OutputStream out) throws Exception{ - PrintWriter w = new PrintWriter(out); - w.print(doc.getText(0, doc.getLength())); - w.close(); + try (PrintWriter w = new PrintWriter(out)) { + w.print(doc.getText(0, doc.getLength())); + } out.close(); } @@ -142,11 +142,10 @@ public static void dumpToFile(DocumentModel model, File f) throws Exception { } public static void dumpToFile(Document doc, File f) throws Exception { - OutputStream out = new BufferedOutputStream(new FileOutputStream(f)); - PrintWriter w = new PrintWriter(out); - w.print(doc.getText(0, doc.getLength())); - w.close(); - out.close(); + try (OutputStream out = new BufferedOutputStream(new FileOutputStream(f)); + PrintWriter w = new PrintWriter(out)) { + w.print(doc.getText(0, doc.getLength())); + } } public static WebBeansModel dumpAndReloadModel(WebBeansModel sm) throws Exception { diff --git a/enterprise/web.el/nbproject/project.xml b/enterprise/web.el/nbproject/project.xml index 58e270eb7a47..13a979e7e9c8 100644 --- a/enterprise/web.el/nbproject/project.xml +++ b/enterprise/web.el/nbproject/project.xml @@ -287,6 +287,15 @@ 2.0 + + org.netbeans.modules.jakarta.web.beans + + + + 1 + 2.0 + + org.netbeans.modules.web.common diff --git a/enterprise/web.el/src/org/netbeans/modules/web/el/refactoring/ELRenameRefactoring.java b/enterprise/web.el/src/org/netbeans/modules/web/el/refactoring/ELRenameRefactoring.java index d40b2679c30e..768776605302 100644 --- a/enterprise/web.el/src/org/netbeans/modules/web/el/refactoring/ELRenameRefactoring.java +++ b/enterprise/web.el/src/org/netbeans/modules/web/el/refactoring/ELRenameRefactoring.java @@ -61,14 +61,23 @@ public ELRenameRefactoring(RenameRefactoring rename) { @Override protected Problem handleClass(CompilationContext info, RefactoringElementsBag refactoringElementsBag, TreePathHandle handle, Element targetType) { TypeElement type = (TypeElement) targetType; - // handles only cases where the managed bean name matches the class name and is not + // handles only cases where the managed bean name matches the class name and is not // explicitly specified in the annotation String beanName = ELVariableResolvers.findBeanName(info, type.getQualifiedName().toString(), getFileObject()); if (beanName != null && beanName.equalsIgnoreCase(type.getSimpleName().toString())) { for (AnnotationMirror ann : info.info().getElements().getAllAnnotationMirrors(type)) { CharSequence annFqn = info.info().getTypeUtilities().getTypeName(ann.getAnnotationType(), TypeNameOptions.PRINT_FQN); if ("javax.faces.bean.ManagedBean".contentEquals(annFqn)) { //NOI18N - for (ExecutableElement annElem : ann.getElementValues().keySet()) { + for (ExecutableElement annElem : ann.getElementValues().keySet()) { + if ("name".contentEquals(annElem.getSimpleName())) { //NOI18N + // name explicitly specified, so don't refactor + return null; + } + } + // uses default name, can be refactored + return super.handleClass(info, refactoringElementsBag, handle, targetType); + } else if ("jakarta.faces.bean.ManagedBean".contentEquals(annFqn)) { //NOI18N + for (ExecutableElement annElem : ann.getElementValues().keySet()) { if ("name".contentEquals(annElem.getSimpleName())) { //NOI18N // name explicitly specified, so don't refactor return null; @@ -78,7 +87,16 @@ protected Problem handleClass(CompilationContext info, RefactoringElementsBag re return super.handleClass(info, refactoringElementsBag, handle, targetType); } if ("javax.inject.Named".contentEquals(annFqn)) { //NOI18N - for (ExecutableElement annElem : ann.getElementValues().keySet()) { + for (ExecutableElement annElem : ann.getElementValues().keySet()) { + if ("value".contentEquals(annElem.getSimpleName())) { //NOI18N + // name explicitly specified, so don't refactor + return null; + } + } + // uses default name, can be refactored + return super.handleClass(info, refactoringElementsBag, handle, targetType); + } else if ("jakarta.inject.Named".contentEquals(annFqn)) { //NOI18N + for (ExecutableElement annElem : ann.getElementValues().keySet()) { if ("value".contentEquals(annElem.getSimpleName())) { //NOI18N // name explicitly specified, so don't refactor return null; diff --git a/enterprise/web.jsf.editor/nbproject/project.xml b/enterprise/web.jsf.editor/nbproject/project.xml index 45b5474cd6cc..e3832f3a336b 100644 --- a/enterprise/web.jsf.editor/nbproject/project.xml +++ b/enterprise/web.jsf.editor/nbproject/project.xml @@ -348,6 +348,15 @@ 2.0 + + org.netbeans.modules.jakarta.web.beans + + + + 1 + 2.0 + + org.netbeans.modules.web.common diff --git a/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/JsfSupportImpl.java b/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/JsfSupportImpl.java index 5ed6faaba43b..9c229e85ec8c 100644 --- a/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/JsfSupportImpl.java +++ b/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/JsfSupportImpl.java @@ -36,8 +36,6 @@ import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; import org.netbeans.modules.parsing.api.Source; import org.netbeans.modules.web.api.webmodule.WebModule; -import org.netbeans.modules.web.beans.MetaModelSupport; -import org.netbeans.modules.web.beans.api.model.WebBeansModel; import org.netbeans.modules.web.jsf.api.facesmodel.JSFVersion; import org.netbeans.modules.web.jsf.editor.facelets.FaceletsLibrarySupport; import org.netbeans.modules.web.jsf.editor.index.JsfIndex; @@ -59,7 +57,7 @@ public class JsfSupportImpl implements JsfSupport { private static final Logger LOG = Logger.getLogger(JsfSupportImpl.class.getSimpleName()); - + public static JsfSupportImpl findFor(Source source) { return getOwnImplementation(JsfSupportProvider.get(source)); } @@ -67,7 +65,7 @@ public static JsfSupportImpl findFor(Source source) { public static JsfSupportImpl findFor(FileObject file) { return getOwnImplementation(JsfSupportProvider.get(file)); } - + private static JsfSupportImpl getOwnImplementation(JsfSupport instance) { if(instance instanceof JsfSupportImpl) { return (JsfSupportImpl)instance; @@ -94,7 +92,7 @@ static JsfSupportImpl findForProject(Project project) { return null; } ClassPath bootCP = ClassPath.getClassPath(webModule.getDocumentBase(), ClassPath.BOOT); - + return new JsfSupportImpl(project, webModule, sourceCP, compileCP, executeCP, bootCP); } else { //non-web project @@ -111,15 +109,15 @@ static JsfSupportImpl findForProject(Project project) { executeCps.add(ClassPath.getClassPath(sg.getRootFolder(), ClassPath.EXECUTE)); bootCps.add(ClassPath.getClassPath(sg.getRootFolder(), ClassPath.BOOT)); } - return new JsfSupportImpl(project, null, + return new JsfSupportImpl(project, null, ClassPathSupport.createProxyClassPath(sourceCps.toArray(new ClassPath[]{})), ClassPathSupport.createProxyClassPath(compileCps.toArray(new ClassPath[]{})), ClassPathSupport.createProxyClassPath(executeCps.toArray(new ClassPath[]{})), ClassPathSupport.createProxyClassPath(bootCps.toArray(new ClassPath[]{}))); } - + } - + //no jsf support for this project return null; } @@ -143,13 +141,14 @@ private static boolean validateUpdateClasspaths(Project project, WebModule webMo return true; } - + private FaceletsLibrarySupport faceletsLibrarySupport; private Project project; private WebModule wm; private ClassPath sourceClassPath, compileClasspath, executeClassPath, bootClassPath; private JsfIndex index; - private MetadataModel webBeansModel; + private MetadataModel webBeansModel; + private MetadataModel webBeansModelJakarta; private Lookup lookup; private JsfSupportImpl(Project project, WebModule wm, ClassPath sourceClassPath, ClassPath compileClassPath, ClassPath executeClassPath, ClassPath bootClassPath) { @@ -172,12 +171,20 @@ public void propertyChange(PropertyChangeEvent evt) { } }); - webBeansModel = new MetaModelSupport(project).getMetaModel(); - + if(isJsf30Plus()){ + webBeansModelJakarta = new org.netbeans.modules.jakarta.web.beans.MetaModelSupport(project).getMetaModel(); + } else { + webBeansModel = new org.netbeans.modules.web.beans.MetaModelSupport(project).getMetaModel(); + } + //init lookup //TODO do it lazy so it creates the web beans model lazily once looked up InstanceContent ic = new InstanceContent(); - ic.add(webBeansModel); + if(isJsf30Plus()){ + ic.add(webBeansModelJakarta); + } else { + ic.add(webBeansModel); + } this.lookup = new AbstractLookup(ic); } @@ -191,7 +198,7 @@ public Project getProject() { public ClassPath getClassPath() { return compileClasspath; } - + public FileObject[] getClassPathRoots() { Collection roots = new ArrayList<>(); roots.addAll(Arrays.asList(sourceClassPath.getRoots())); @@ -218,15 +225,15 @@ public Library getLibrary(String namespace) { return NamespaceUtils.getForNs(faceletsLibrarySupport.getLibraries(), namespace); } - /** Library's uri to library map - * Please note that a composite components library can be preset twice in the values. + /** Library's uri to library map + * Please note that a composite components library can be preset twice in the values. * Once under the declared namespace key and once under the default cc namespace key. */ @Override public Map getLibraries() { return faceletsLibrarySupport.getLibraries(); } - + public boolean isFileOnClasspath(FileObject file) { return sourceClassPath.contains(file) || compileClasspath.contains(file) @@ -239,7 +246,7 @@ public boolean isFileOnClasspath(FileObject file) { public void indexedContentPossiblyChanged() { faceletsLibrarySupport.indexedContentPossiblyChanged(); } - + //garbage methods below, needs cleanup! public synchronized JsfIndex getIndex() { if(index == null) { @@ -252,9 +259,13 @@ public FaceletsLibrarySupport getFaceletsLibrarySupport() { return faceletsLibrarySupport; } - public synchronized MetadataModel getWebBeansModel() { + public synchronized MetadataModel getWebBeansModel() { return webBeansModel; } + + public synchronized MetadataModel getJakartaWebBeansModel() { + return webBeansModelJakarta; + } @Override public boolean isJsf22Plus() { @@ -267,6 +278,17 @@ public boolean isJsf22Plus() { return true; } + @Override + public boolean isJsf30Plus() { + if (wm != null) { + JSFVersion version = JSFVersion.forWebModule(wm); + // caching is done inside the method + return version != null && version.isAtLeast(JSFVersion.JSF_3_0); + } + // return the latest supported one until somebody will complain about that + return true; + } + @Override public String toString() { return String.format("JsfSupportImpl[%s]", getBaseFile().getPath()); //NOI18N diff --git a/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/el/WebBeansELVariableResolver.java b/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/el/WebBeansELVariableResolver.java index d6e9f8260570..2681086d29a8 100644 --- a/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/el/WebBeansELVariableResolver.java +++ b/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/el/WebBeansELVariableResolver.java @@ -54,7 +54,7 @@ public FieldInfo getInjectableField(String beanName, FileObject target, Resolver } return null; } - + @Override public String getBeanName(String clazz, FileObject target, ResolverContext context) { for (WebBean bean : getWebBeans(target, context)) { @@ -101,7 +101,11 @@ private List getWebBeans(FileObject target, ResolverContext context) { return Collections.emptyList(); } else { if (context.getContent(CONTENT_NAME) == null) { - context.setContent(CONTENT_NAME, getNamedBeans(jsfSupport.getWebBeansModel())); + if(jsfSupport.isJsf30Plus()){ + context.setContent(CONTENT_NAME, getJakartaNamedBeans(jsfSupport.getJakartaWebBeansModel())); + } else { + context.setContent(CONTENT_NAME, getNamedBeans(jsfSupport.getWebBeansModel())); + } } return (List) context.getContent(CONTENT_NAME); } @@ -109,21 +113,40 @@ private List getWebBeans(FileObject target, ResolverContext context) { private static List getNamedBeans(MetadataModel webBeansModel) { try { - return webBeansModel.runReadAction(new MetadataModelAction>() { - - @Override - public List run(WebBeansModel metadata) throws Exception { - List namedElements = metadata.getNamedElements(); - List webBeans = new LinkedList<>(); - for (Element e : namedElements) { - //filter out null elements - probably a WebBeansModel bug, - //happens under some circumstances when renaming/deleting beans - if (e != null) { - webBeans.add(new WebBean(e, metadata.getName(e))); - } + return webBeansModel.runReadAction((WebBeansModel metadata) -> { + List namedElements = metadata.getNamedElements(); + List webBeans = new LinkedList<>(); + for (Element e : namedElements) { + //filter out null elements - probably a WebBeansModel bug, + //happens under some circumstances when renaming/deleting beans + if (e != null) { + webBeans.add(new WebBean(e, metadata.getName(e))); + } + } + return webBeans; + }); + } catch (MetadataModelException ex) { + Exceptions.printStackTrace(ex); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + + return Collections.emptyList(); + } + + private static List getJakartaNamedBeans(MetadataModel webBeansModel) { + try { + return webBeansModel.runReadAction(metadata -> { + List namedElements = metadata.getNamedElements(); + List webBeans = new LinkedList<>(); + for (Element e : namedElements) { + //filter out null elements - probably a WebBeansModel bug, + //happens under some circumstances when renaming/deleting beans + if (e != null) { + webBeans.add(new WebBean(e, metadata.getName(e))); } - return webBeans; } + return webBeans; }); } catch (MetadataModelException ex) { Exceptions.printStackTrace(ex); @@ -172,5 +195,5 @@ private String getEnclodingClass() { } } } - + } diff --git a/enterprise/web.jsf/manifest.mf b/enterprise/web.jsf/manifest.mf index 84239c0d65bf..1a1da359e2dd 100644 --- a/enterprise/web.jsf/manifest.mf +++ b/enterprise/web.jsf/manifest.mf @@ -2,7 +2,7 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.modules.web.jsf/1 OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/web/jsf/resources/Bundle.properties OpenIDE-Module-Layer: org/netbeans/modules/web/jsf/resources/layer.xml -OpenIDE-Module-Implementation-Version: 2 +OpenIDE-Module-Implementation-Version: 3 OpenIDE-Module-Needs: javax.script.ScriptEngine.freemarker OpenIDE-Module-Recommends: org.netbeans.modules.web.jsf.complib AutoUpdate-Show-In-Client: false diff --git a/enterprise/web.jsf/nbproject/project.xml b/enterprise/web.jsf/nbproject/project.xml index 302a68e2c764..f7dcc46e2240 100644 --- a/enterprise/web.jsf/nbproject/project.xml +++ b/enterprise/web.jsf/nbproject/project.xml @@ -443,6 +443,15 @@ 2.3 + + org.netbeans.modules.jakarta.web.beans + + + + 1 + 2.3 + + org.netbeans.modules.web.common diff --git a/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/JSFUtils.java b/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/JSFUtils.java index 55bc739b8dcf..065ebcf3672a 100644 --- a/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/JSFUtils.java +++ b/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/JSFUtils.java @@ -325,6 +325,16 @@ public static boolean isJavaEE5(TemplateWizard wizard) { } return false; } + + public static boolean isJakartaEE9Plus(TemplateWizard wizard) { + Project project = Templates.getProject(wizard); + WebModule wm = WebModule.getWebModule(project.getProjectDirectory()); + if (wm != null) { + Profile profile = wm.getJ2eeProfile(); + return profile.isAtLeast(Profile.JAKARTA_EE_9_WEB); + } + return false; + } /** * Logs usage statistics data. diff --git a/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/hints/rules/FlowScopedBeanWithoutCdi.java b/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/hints/rules/FlowScopedBeanWithoutCdi.java index 9f9446fc012e..df0caff548eb 100644 --- a/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/hints/rules/FlowScopedBeanWithoutCdi.java +++ b/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/hints/rules/FlowScopedBeanWithoutCdi.java @@ -29,7 +29,6 @@ import org.netbeans.api.project.Project; import org.netbeans.api.project.ProjectInformation; import org.netbeans.api.project.ProjectUtils; -import org.netbeans.modules.web.beans.CdiUtil; import org.netbeans.modules.web.jsf.hints.JsfHintsContext; import org.netbeans.modules.web.jsf.hints.JsfHintsUtils; import org.netbeans.spi.editor.hints.ChangeInfo; @@ -60,6 +59,7 @@ public class FlowScopedBeanWithoutCdi { private static final String FLOW_SCOPED = "javax.faces.flow.FlowScoped"; //NOI18N + private static final String FLOW_SCOPED_JAKARTA = "jakarta.faces.flow.FlowScoped"; //NOI18N @TriggerTreeKind(Tree.Kind.CLASS) public static Collection run(HintContext hintContext) { @@ -76,7 +76,19 @@ public static Collection run(HintContext hintContext) { for (AnnotationMirror annotationMirror : typeElement.getAnnotationMirrors()) { if (FLOW_SCOPED.equals(annotationMirror.getAnnotationType().toString())) { // it's FlowScoped bean -> check the CDI - CdiUtil cdiUtil = project.getLookup().lookup(CdiUtil.class); + org.netbeans.modules.web.beans.CdiUtil cdiUtil = project.getLookup().lookup(org.netbeans.modules.web.beans.CdiUtil.class); + if (cdiUtil == null || !cdiUtil.isCdiEnabled()) { + Tree tree = info.getTrees().getTree(typeElement, annotationMirror); + problems.add(JsfHintsUtils.createProblem( + tree, + info, + Bundle.FlowScopedBeanWithoutCdi_display_name(), + Severity.WARNING, + Arrays.asList(new FixCdiAvailability(project)))); + } + } else if (FLOW_SCOPED_JAKARTA.equals(annotationMirror.getAnnotationType().toString())) { + // it's FlowScoped bean -> check the CDI + org.netbeans.modules.jakarta.web.beans.CdiUtil cdiUtil = project.getLookup().lookup(org.netbeans.modules.jakarta.web.beans.CdiUtil.class); if (cdiUtil == null || !cdiUtil.isCdiEnabled()) { Tree tree = info.getTrees().getTree(typeElement, annotationMirror); problems.add(JsfHintsUtils.createProblem( @@ -115,7 +127,11 @@ public String getText() { @Override public ChangeInfo implement() throws Exception { - CdiUtil cdiUtil = project.getLookup().lookup(CdiUtil.class); + org.netbeans.modules.jakarta.web.beans.CdiUtil jakartaCdiUtil = project.getLookup().lookup(org.netbeans.modules.jakarta.web.beans.CdiUtil.class); + if (jakartaCdiUtil != null) { + jakartaCdiUtil.enableCdi(); + } + org.netbeans.modules.web.beans.CdiUtil cdiUtil = project.getLookup().lookup(org.netbeans.modules.web.beans.CdiUtil.class); if (cdiUtil != null) { cdiUtil.enableCdi(); } diff --git a/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/palette/items/JsfLibrariesSupport.java b/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/palette/items/JsfLibrariesSupport.java index 4f9cd85425d6..235e1f9adfeb 100644 --- a/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/palette/items/JsfLibrariesSupport.java +++ b/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/palette/items/JsfLibrariesSupport.java @@ -98,7 +98,7 @@ public void run(ResultIterator resultIterator) throws Exception { Map> ns2prefixes = htmlresult != null ? htmlresult.getSyntaxAnalyzerResult().getAllDeclaredNamespaces() : Collections.>emptyMap(); - + for (DefaultLibraryInfo libraryInfo : DefaultLibraryInfo.values()) { LibraryImport libraryimport = new LibraryImport(); @@ -146,6 +146,10 @@ public boolean isJsf22Plus() { return jsfs.isJsf22Plus(); } + public boolean isJsf30Plus() { + return jsfs.isJsf30Plus(); + } + private static class LibraryImport { public Library lib; public String declaredPrefix; diff --git a/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/palette/items/ManagedBeanCustomizer.java b/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/palette/items/ManagedBeanCustomizer.java index c7476fbfa1ae..54bf10e68bc2 100644 --- a/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/palette/items/ManagedBeanCustomizer.java +++ b/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/palette/items/ManagedBeanCustomizer.java @@ -59,12 +59,11 @@ import org.netbeans.modules.j2ee.persistence.wizard.EntityClosure; import org.netbeans.modules.j2ee.persistence.wizard.jpacontroller.JpaControllerUtil; import org.netbeans.modules.web.api.webmodule.WebModule; -import org.netbeans.modules.web.beans.MetaModelSupport; -import org.netbeans.modules.web.beans.api.model.WebBeansModel; import org.netbeans.modules.web.jsf.JsfTemplateUtils; import org.netbeans.modules.web.jsf.JsfTemplateUtils.OpenTemplateAction; import org.netbeans.modules.web.jsf.JsfTemplateUtils.TemplateType; import org.netbeans.modules.web.jsf.api.editor.JSFBeanCache; +import org.netbeans.modules.web.jsf.api.facesmodel.JSFVersion; import org.netbeans.modules.web.jsf.api.metamodel.FacesManagedBean; import org.netbeans.spi.java.classpath.support.ClassPathSupport; import org.openide.DialogDescriptor; @@ -84,7 +83,8 @@ public class ManagedBeanCustomizer extends javax.swing.JPanel implements Cancell public static final String TABLE_TEMPLATE = "table.ftl"; // NOI18N private Project project; - private MetaModelSupport metaModelSupport; + private org.netbeans.modules.web.beans.MetaModelSupport metaModelSupport; + private org.netbeans.modules.jakarta.web.beans.MetaModelSupport jakartaMetaModelSupport; private boolean collection; private boolean dummyBean = false; private Dialog dialog; @@ -113,7 +113,13 @@ public void contentsChanged(ListDataEvent e) { } }); this.project = project; - this.metaModelSupport = new MetaModelSupport(project); + JSFVersion projectJsfVersion = JSFVersion.forProject(project); + if(projectJsfVersion != null && projectJsfVersion.isAtLeast(JSFVersion.JSF_4_0)){ + this.jakartaMetaModelSupport = new org.netbeans.modules.jakarta.web.beans.MetaModelSupport(project); + } else { + this.metaModelSupport = new org.netbeans.modules.web.beans.MetaModelSupport(project); + } + this.collection = collection; readOnlyCheckBox.setVisible(enableReadOnly); hint.setVisible(false); @@ -367,9 +373,10 @@ public List getPropertyNames(final Project project, final String entityC } try { //check web beans - metaModelSupport.getMetaModel().runReadAction(new MetadataModelAction() { + if(JSFVersion.forProject(project) == JSFVersion.JSF_4_0){ + jakartaMetaModelSupport.getMetaModel().runReadAction(new MetadataModelAction() { @Override - public Void run(WebBeansModel metadata) throws Exception { + public Void run(org.netbeans.modules.jakarta.web.beans.api.model.WebBeansModel metadata) throws Exception { for (Element bean : metadata.getNamedElements()) { if (bean == null) { continue; @@ -382,7 +389,25 @@ public Void run(WebBeansModel metadata) throws Exception { } return null; } - }); + }); + } else { + metaModelSupport.getMetaModel().runReadAction(new MetadataModelAction() { + @Override + public Void run(org.netbeans.modules.web.beans.api.model.WebBeansModel metadata) throws Exception { + for (Element bean : metadata.getNamedElements()) { + if (bean == null) { + continue; + } + String beanName = metadata.getName(bean); + String className = bean.asType().toString(); + if ((beanName != null)) { + res.addAll(getManagedBeanPropertyNames(project, className, entityClass, beanName, collection)); + } + } + return null; + } + }); + } } catch (MetadataModelException ex) { Exceptions.printStackTrace(ex); } catch (IOException ex) { @@ -439,7 +464,7 @@ private class SearchTask implements Task { private final List result; private boolean scanning; - public SearchTask(String managedBean, String entityClassName, String managedBeanName, + public SearchTask(String managedBean, String entityClassName, String managedBeanName, List result, boolean scanning) { this.managedBean = managedBean; this.entityClassName = entityClassName; diff --git a/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/wizards/ManagedBeanIterator.java b/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/wizards/ManagedBeanIterator.java index fa44188bbfe4..049c2e40fc9e 100644 --- a/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/wizards/ManagedBeanIterator.java +++ b/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/wizards/ManagedBeanIterator.java @@ -34,7 +34,6 @@ import org.netbeans.api.project.SourceGroup; import org.netbeans.api.project.Sources; import org.netbeans.modules.web.api.webmodule.WebModule; -import org.netbeans.modules.web.beans.CdiUtil; import org.netbeans.modules.web.jsf.JSFConfigUtilities; import org.netbeans.modules.web.jsf.JSFUtils; import org.netbeans.modules.web.jsf.api.ConfigurationUtils; @@ -165,8 +164,19 @@ public Set instantiate(TemplateWizard wizard) throws IOException { if (isAnnotate && (Utilities.isJavaEE6Plus(wizard) || (JSFUtils.isJSF20Plus(wm, true) && JSFUtils.isJavaEE5(wizard)))) { Map templateProperties = new HashMap(); String targetName = Templates.getTargetName(wizard); - CdiUtil cdiUtil = project.getLookup().lookup(CdiUtil.class); - if (cdiUtil != null && cdiUtil.isCdiEnabled()) { + boolean isCdiEnabled = false; + if(JSFUtils.isJakartaEE9Plus(wizard)) { + org.netbeans.modules.jakarta.web.beans.CdiUtil cdiUtil = project.getLookup().lookup(org.netbeans.modules.jakarta.web.beans.CdiUtil.class); + if(cdiUtil != null && cdiUtil.isCdiEnabled()){ + isCdiEnabled = true; + } + } else { + org.netbeans.modules.web.beans.CdiUtil cdiUtil = project.getLookup().lookup(org.netbeans.modules.web.beans.CdiUtil.class); + if(cdiUtil != null && cdiUtil.isCdiEnabled()){ + isCdiEnabled = true; + } + } + if (isCdiEnabled) { templateProperties.put("cdiEnabled", true); templateProperties.put("classAnnotation", "@Named(value=\"" + beanName + "\")"); //NOI18N templateProperties.put("scope", ScopeEntry.getFor(scope)); //NOI18N diff --git a/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/wizards/ManagedBeanPanelVisual.java b/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/wizards/ManagedBeanPanelVisual.java index e197749f9ea8..3080e732f2f2 100644 --- a/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/wizards/ManagedBeanPanelVisual.java +++ b/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/wizards/ManagedBeanPanelVisual.java @@ -41,6 +41,7 @@ import org.netbeans.modules.web.jsf.api.facesmodel.FacesConfig; import org.netbeans.modules.web.jsf.api.facesmodel.JSFVersion; import org.netbeans.modules.web.jsf.api.facesmodel.ManagedBean; +import org.netbeans.modules.web.jsf.palette.items.JsfLibrariesSupport; import org.netbeans.modules.web.jsf.wizards.ManagedBeanIterator.NamedScope; import org.netbeans.modules.web.wizards.Utilities; import org.netbeans.spi.project.ui.templates.support.Templates; @@ -66,6 +67,7 @@ public ManagedBeanPanelVisual(Project proj) { boolean addToFacesConfig = false; WebModule wm = WebModule.getWebModule(proj.getProjectDirectory()); + Profile profile = null; if (wm != null){ String[] configFiles = JSFConfigUtilities.getConfigFiles(wm); if (configFiles.length > 0){ @@ -83,7 +85,7 @@ public ManagedBeanPanelVisual(Project proj) { addToConfigCheckBox.setEnabled(false); jComboBoxConfigFile.setEnabled(false); } else { - Profile profile = wm.getJ2eeProfile(); + profile = wm.getJ2eeProfile(); if (profile != null && !profile.isAtLeast(Profile.JAVA_EE_6_WEB)) { addToFacesConfig = true; addToConfigCheckBox.setSelected(true); @@ -93,8 +95,13 @@ public ManagedBeanPanelVisual(Project proj) { } } Object[] scopes; - CdiUtil cdiUtil = proj.getLookup().lookup(CdiUtil.class); - isCDIEnabled = cdiUtil != null && cdiUtil.isCdiEnabled(); + if(profile != null && (profile.isAtLeast(Profile.JAKARTA_EE_9_WEB))){ + org.netbeans.modules.jakarta.web.beans.CdiUtil cdiUtil = proj.getLookup().lookup(org.netbeans.modules.jakarta.web.beans.CdiUtil.class); + isCDIEnabled = cdiUtil != null && cdiUtil.isCdiEnabled(); + } else { + org.netbeans.modules.web.beans.CdiUtil cdiUtil = proj.getLookup().lookup(org.netbeans.modules.web.beans.CdiUtil.class); + isCDIEnabled = cdiUtil != null && cdiUtil.isCdiEnabled(); + } if (isCDIEnabled && !addToFacesConfig) { scopes = ManagedBeanIterator.NamedScope.values(); } else { diff --git a/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/wizards/PersistenceClientIterator.java b/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/wizards/PersistenceClientIterator.java index bb4ad1ab44c9..eac925477d5d 100644 --- a/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/wizards/PersistenceClientIterator.java +++ b/enterprise/web.jsf/src/org/netbeans/modules/web/jsf/wizards/PersistenceClientIterator.java @@ -632,8 +632,15 @@ private static boolean showImportStatement(String packageName, String fqn) { } private static boolean isCdiEnabled(Project project) { - CdiUtil cdiUtil = project.getLookup().lookup(CdiUtil.class); - return (cdiUtil == null) ? false : cdiUtil.isCdiEnabled(); + org.netbeans.modules.jakarta.web.beans.CdiUtil jakartaCdiUtil = project.getLookup().lookup(org.netbeans.modules.jakarta.web.beans.CdiUtil.class); + if(jakartaCdiUtil != null && jakartaCdiUtil.isCdiEnabled()) { + return true; + } + org.netbeans.modules.web.beans.CdiUtil javaxCdiUtil = project.getLookup().lookup(org.netbeans.modules.web.beans.CdiUtil.class); + if(javaxCdiUtil != null && javaxCdiUtil.isCdiEnabled()) { + return true; + } + return false; } private static ResourceBundle findBundle(JSFConfigModel model, ResourceBundle rb) { diff --git a/enterprise/web.jsfapi/nbproject/org-netbeans-modules-web-jsfapi.sig b/enterprise/web.jsfapi/nbproject/org-netbeans-modules-web-jsfapi.sig index 56b8cf0702c8..2f8b6d31a2ee 100644 --- a/enterprise/web.jsfapi/nbproject/org-netbeans-modules-web-jsfapi.sig +++ b/enterprise/web.jsfapi/nbproject/org-netbeans-modules-web-jsfapi.sig @@ -1,5 +1,5 @@ #Signature file v4.1 -#Version 1.53 +#Version 1.55 CLSS public abstract interface java.io.Serializable @@ -124,6 +124,7 @@ meth public abstract java.lang.String getSignature() CLSS public abstract interface org.netbeans.modules.web.jsfapi.api.JsfSupport meth public abstract boolean isJsf22Plus() +meth public abstract boolean isJsf30Plus() meth public abstract java.util.Map getLibraries() meth public abstract org.netbeans.api.java.classpath.ClassPath getClassPath() meth public abstract org.netbeans.api.project.Project getProject() diff --git a/enterprise/web.jsfapi/src/org/netbeans/modules/web/jsfapi/api/JsfSupport.java b/enterprise/web.jsfapi/src/org/netbeans/modules/web/jsfapi/api/JsfSupport.java index eacb14f446f3..34572bc3e1b6 100644 --- a/enterprise/web.jsfapi/src/org/netbeans/modules/web/jsfapi/api/JsfSupport.java +++ b/enterprise/web.jsfapi/src/org/netbeans/modules/web/jsfapi/api/JsfSupport.java @@ -38,13 +38,15 @@ public interface JsfSupport { public WebModule getWebModule(); public Library getLibrary(String namespace); - + /** * @return Library namespace to Library instance map */ public Map getLibraries(); - + public Lookup getLookup(); public boolean isJsf22Plus(); + + public boolean isJsf30Plus(); } diff --git a/enterprise/web.kit/nbproject/project.xml b/enterprise/web.kit/nbproject/project.xml index 34e7a828fe47..c2cbfa53f93a 100644 --- a/enterprise/web.kit/nbproject/project.xml +++ b/enterprise/web.kit/nbproject/project.xml @@ -152,6 +152,13 @@ 2.0 + + org.netbeans.modules.jakarta.web.beans + + 1 + 2.0 + + org.netbeans.modules.web.client.kit diff --git a/ide/xml.text/nbproject/project.xml b/ide/xml.text/nbproject/project.xml index 6fde092add0d..397da71df302 100644 --- a/ide/xml.text/nbproject/project.xml +++ b/ide/xml.text/nbproject/project.xml @@ -437,6 +437,7 @@ org.netbeans.modules.hibernate org.netbeans.modules.j2ee.persistence + org.netbeans.modules.jakarta.web.beans org.netbeans.modules.javafx2.editor org.netbeans.modules.spring.beans org.netbeans.modules.wag.manager diff --git a/java/j2ee.metadata.model.support/nbproject/project.xml b/java/j2ee.metadata.model.support/nbproject/project.xml index 7eadca133efe..29fb183836d7 100644 --- a/java/j2ee.metadata.model.support/nbproject/project.xml +++ b/java/j2ee.metadata.model.support/nbproject/project.xml @@ -156,6 +156,7 @@ org.netbeans.modules.javaee.resources org.netbeans.modules.spring.beans org.netbeans.modules.web.beans + org.netbeans.modules.jakarta.web.beans org.netbeans.modules.web.jsf org.netbeans.modules.websvc.restapi org.netbeans.modules.j2ee.metadata.model.api.support.annotation diff --git a/java/java.hints.legacy.spi/nbproject/project.xml b/java/java.hints.legacy.spi/nbproject/project.xml index f70be06315f3..aad67103ca00 100644 --- a/java/java.hints.legacy.spi/nbproject/project.xml +++ b/java/java.hints.legacy.spi/nbproject/project.xml @@ -128,6 +128,7 @@ org.netbeans.modules.ant.hints org.netbeans.modules.apisupport.ant org.netbeans.modules.java.lsp.server + org.netbeans.modules.jakarta.web.beans org.netbeans.modules.javadoc org.netbeans.modules.javahints org.netbeans.modules.jshell.support diff --git a/java/java.lsp.server/nbcode/nbproject/platform.properties b/java/java.lsp.server/nbcode/nbproject/platform.properties index 3980d1e377ed..2e16c1e7b0e0 100644 --- a/java/java.lsp.server/nbcode/nbproject/platform.properties +++ b/java/java.lsp.server/nbcode/nbproject/platform.properties @@ -344,6 +344,7 @@ disabled.modules=\ org.netbeans.modules.j2ee.sun.appsrv,\ org.netbeans.modules.j2ee.sun.dd,\ org.netbeans.modules.j2ee.sun.ddui,\ + org.netbeans.modules.jakarta.web.beans,\ org.netbeans.modules.jakartaee8.api,\ org.netbeans.modules.jakartaee8.platform,\ org.netbeans.modules.javaee7.api,\ diff --git a/java/javaee.injection/nbproject/project.xml b/java/javaee.injection/nbproject/project.xml index 9f139cb84e8d..2d873cf3414d 100644 --- a/java/javaee.injection/nbproject/project.xml +++ b/java/javaee.injection/nbproject/project.xml @@ -63,6 +63,7 @@ org.netbeans.modules.j2ee.common org.netbeans.modules.j2ee.ejbcore org.netbeans.modules.j2ee.persistence + org.netbeans.modules.jakarta.web.beans org.netbeans.modules.maven.j2ee org.netbeans.modules.maven.jaxws org.netbeans.modules.web.beans diff --git a/nbbuild/cluster.properties b/nbbuild/cluster.properties index 274f65de5d58..50ff97b09201 100644 --- a/nbbuild/cluster.properties +++ b/nbbuild/cluster.properties @@ -764,6 +764,7 @@ nb.cluster.enterprise=\ j2ee.sun.ddui,\ j2eeapis,\ j2eeserver,\ + jakarta.web.beans,\ jakartaee10.api,\ jakartaee10.platform,\ jakartaee8.api,\