polygene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nic...@apache.org
Subject [55/80] zest-java git commit: Stage 2 of the namespace change. Bulk of documentation fixed.
Date Thu, 30 Jul 2015 19:48:54 GMT
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/concerns/inspections/ConcernsAnnotationDeclaredCorrectlyInspection.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/concerns/inspections/ConcernsAnnotationDeclaredCorrectlyInspection.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/concerns/inspections/ConcernsAnnotationDeclaredCorrectlyInspection.java
new file mode 100644
index 0000000..fc598d5
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/concerns/inspections/ConcernsAnnotationDeclaredCorrectlyInspection.java
@@ -0,0 +1,173 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.concerns.inspections;
+
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiAnnotationMemberValue;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiJavaCodeReferenceElement;
+import com.intellij.psi.search.GlobalSearchScope;
+import org.jetbrains.annotations.NotNull;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractFix;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractInspection;
+import org.apache.zest.ide.plugin.idea.common.resource.Qi4jResourceBundle;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.intellij.codeInspection.ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
+import static org.apache.zest.ide.plugin.idea.common.psi.search.GlobalSearchScopeUtil.determineSearchScope;
+import static org.apache.zest.ide.plugin.idea.common.resource.Qi4jResourceBundle.message;
+import static org.apache.zest.ide.plugin.idea.concerns.common.Qi4jConcernUtil.*;
+
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class ConcernsAnnotationDeclaredCorrectlyInspection extends AbstractInspection
+{
+    @NotNull
+    protected final String resourceBundlePrefixId()
+    {
+        return "concerns.annotation.declared.correctly";
+    }
+
+    @NotNull
+    public final String getShortName()
+    {
+        return "ConcernsAnnotationDeclaredCorrectlyInspection";
+    }
+
+    @Override
+    public final ProblemDescriptor[] checkClass( @NotNull PsiClass psiClass,
+                                                 @NotNull InspectionManager manager,
+                                                 boolean isOnTheFly )
+    {
+        // If class does not have @Concerns, ignore
+        PsiAnnotation concernsAnnotation = getConcernsAnnotation( psiClass );
+        if( concernsAnnotation == null )
+        {
+            return null;
+        }
+
+        // If @Concerns declared in class, suggest remove @Concerns annotation
+        if( !psiClass.isInterface() )
+        {
+            String message = message( "concerns.annotation.declared.correctly.error.annotation.declared.in.class" );
+            RemoveConcernsAnnotationFix fix = new RemoveConcernsAnnotationFix( concernsAnnotation );
+            ProblemDescriptor problemDescriptor = manager.createProblemDescriptor( concernsAnnotation, message, fix,
+                                                                                   GENERIC_ERROR_OR_WARNING );
+            return new ProblemDescriptor[]{ problemDescriptor };
+        }
+
+        // If @Concerns annotation is empty, ignore
+        List<PsiAnnotationMemberValue> concernsAnnotationValue = getConcernsAnnotationValue( concernsAnnotation );
+        if( concernsAnnotationValue.isEmpty() )
+        {
+            return null;
+        }
+
+        // If ConcernOfClass is not resolved, ignore
+        Project project = psiClass.getProject();
+        GlobalSearchScope searchScope = determineSearchScope( psiClass );
+        PsiClass concernOfClass = getConcernOfClass( project, searchScope );
+        if( concernOfClass == null )
+        {
+            return null;
+        }
+
+        List<ProblemDescriptor> problems = new LinkedList<ProblemDescriptor>();
+        for( PsiAnnotationMemberValue concernClassAnnotationValue : concernsAnnotationValue )
+        {
+            PsiJavaCodeReferenceElement concernClassReference = getConcernClassReference( concernClassAnnotationValue );
+
+            // If it's not a class reference, ignore
+            if( concernClassReference == null )
+            {
+                continue;
+            }
+
+            // If class reference can't be resolved, ignore
+            PsiClass concernClass = (PsiClass) concernClassReference.resolve();
+            if( concernClass == null )
+            {
+                continue;
+            }
+
+            // If concern class does not inherit concern class, suggest remove that reference.
+            if( !concernClass.isInheritor( concernOfClass, true ) )
+            {
+                String message = Qi4jResourceBundle.message(
+                    "concerns.annotation.declared.correctly.error.concern.class.does.not.extend.ConcernOf",
+                    concernClass.getQualifiedName()
+                );
+
+                RemoveInvalidConcernClassReferenceFix fix = new RemoveInvalidConcernClassReferenceFix(
+                    concernClassAnnotationValue, concernClassReference
+                );
+                ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(
+                    concernClassAnnotationValue, message, fix, GENERIC_ERROR_OR_WARNING );
+                problems.add( problemDescriptor );
+            }
+            else
+            {
+                // TODO: Test whether it is a generic concern
+                // TODO: Test whether it is a specific concern
+            }
+        }
+
+        return problems.toArray( new ProblemDescriptor[problems.size()] );
+    }
+
+    private static class RemoveConcernsAnnotationFix extends AbstractFix
+    {
+        private final PsiAnnotation annotationToRemove;
+
+        private RemoveConcernsAnnotationFix( @NotNull PsiAnnotation annotationToRemove )
+        {
+            super( message( "concerns.annotation.declared.correctly.fix.remove.annotation" ) );
+            this.annotationToRemove = annotationToRemove;
+        }
+
+        public final void applyFix( @NotNull Project project, @NotNull ProblemDescriptor descriptor )
+        {
+            annotationToRemove.delete();
+        }
+    }
+
+    private static class RemoveInvalidConcernClassReferenceFix extends AbstractFix
+    {
+        private final PsiAnnotationMemberValue concernClassAnnotationValue;
+
+        public RemoveInvalidConcernClassReferenceFix( @NotNull PsiAnnotationMemberValue annotationValueToRemove,
+                                                      @NotNull PsiJavaCodeReferenceElement concernClassReference )
+        {
+            super( message( "concerns.annotation.declared.correctly.fix.remove.concern.class.reference",
+                            concernClassReference.getQualifiedName() ) );
+            this.concernClassAnnotationValue = annotationValueToRemove;
+        }
+
+        public final void applyFix( @NotNull Project project, @NotNull ProblemDescriptor descriptor )
+        {
+            concernClassAnnotationValue.delete();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/concerns/intentions/add/AddConcernOnType.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/concerns/intentions/add/AddConcernOnType.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/concerns/intentions/add/AddConcernOnType.java
new file mode 100644
index 0000000..9a06c04
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/concerns/intentions/add/AddConcernOnType.java
@@ -0,0 +1,138 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.concerns.intentions.add;
+
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.util.Processor;
+import com.intellij.util.Query;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.apache.zest.ide.plugin.idea.common.intentions.AbstractIntention;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.intellij.psi.search.searches.ClassInheritorsSearch.search;
+import static java.util.Collections.emptyList;
+import static org.apache.zest.ide.plugin.idea.common.psi.search.GlobalSearchScopeUtil.determineSearchScope;
+import static org.apache.zest.ide.plugin.idea.concerns.common.Qi4jConcernUtil.addOrReplaceConcernAnnotation;
+import static org.apache.zest.ide.plugin.idea.concerns.common.Qi4jConcernUtil.getConcernOfClass;
+
+/**
+ * JAVADOC: This is disabled in Qi4jApplicationComponent.
+ *
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class AddConcernOnType
+    extends AbstractIntention
+{
+    protected boolean isIntentionValidFor( PsiElement element )
+    {
+        if( !( element instanceof PsiClass ) )
+        {
+            return false;
+        }
+
+        // If it's not interface, ignore it
+        PsiClass psiClass = (PsiClass) element;
+        if( !psiClass.isInterface() )
+        {
+            return false;
+        }
+
+        // Is @Concerns accesible within module
+        GlobalSearchScope searchScope = determineSearchScope( psiClass );
+        PsiClass concernOfClass = getConcernOfClass( psiClass.getProject(), searchScope );
+        return concernOfClass != null;
+    }
+
+    protected final String resourceBundlePrefixId()
+    {
+        return "add.concern";
+    }
+
+    @Override
+    public boolean isAvailable( @NotNull Project project, Editor editor, @Nullable PsiElement element )
+    {
+        while( element != null )
+        {
+            if( element instanceof PsiFile ||
+                element instanceof PsiMethod )
+            {
+                break;
+            }
+
+            if( isIntentionValidFor( element ) )
+            {
+                return true;
+            }
+
+            element = element.getParent();
+        }
+
+        return false;
+    }
+
+    @SuppressWarnings( "unchecked" )
+    protected void processIntention( @NotNull Project project, @NotNull Editor editor, @NotNull PsiElement element )
+    {
+        PsiClass psiClass = (PsiClass) element;
+        List<PsiClass> concernCandidates = findConcernsCandidates( psiClass );
+        if( concernCandidates.size() == 1 )
+        {
+            PsiClass concernCandidate = concernCandidates.get( 0 );
+            addOrReplaceConcernAnnotation( psiClass, concernCandidate );
+        }
+    }
+
+    private static List<PsiClass> findConcernsCandidates( final @NotNull PsiClass classToCheck )
+    {
+        GlobalSearchScope searchScope = determineSearchScope( classToCheck );
+        PsiClass concernOfClass = getConcernOfClass( classToCheck.getProject(), searchScope );
+        if( concernOfClass == null )
+        {
+            return emptyList();
+        }
+
+        Query<PsiClass> psiClassQuery = search( concernOfClass, searchScope, true, false );
+        final List<PsiClass> concernCandidates = new ArrayList<PsiClass>();
+        psiClassQuery.forEach( new Processor<PsiClass>()
+        {
+            public boolean process( PsiClass psiClass )
+            {
+                // TODO: Ideally search for all "extends" as well
+                boolean isInheritor = psiClass.isInheritor( classToCheck, true );
+                if( isInheritor )
+                {
+                    concernCandidates.add( psiClass );
+                }
+
+                return true;
+            }
+        } );
+
+        return concernCandidates;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/common/inspections/AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/common/inspections/AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/common/inspections/AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection.java
new file mode 100644
index 0000000..d84fb33
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/common/inspections/AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection.java
@@ -0,0 +1,90 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.injections.common.inspections;
+
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiParameter;
+import com.intellij.psi.PsiParameterList;
+import org.jetbrains.annotations.NotNull;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractFix;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.intellij.codeInspection.ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
+import static java.util.Arrays.asList;
+
+/**
+ * {@code AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection} is a helper method to check whether
+ * injection annotation are declared in either constructor or non static field.
+ *
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public abstract class AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection
+    extends AbstractInjectionAnnotationDeclarationOnFieldInspection
+{
+    @Override
+    public final ProblemDescriptor[] checkMethod( @NotNull PsiMethod method,
+                                                  @NotNull InspectionManager manager,
+                                                  boolean isOnTheFly )
+    {
+        PsiParameterList parameterList = method.getParameterList();
+        PsiParameter[] parameters = parameterList.getParameters();
+        if( method.isConstructor() )
+        {
+            List<ProblemDescriptor> problems = new LinkedList<ProblemDescriptor>();
+            for( PsiParameter parameter : parameters )
+            {
+                PsiAnnotation annotation = getAnnotationToCheck( parameter );
+                if( annotation != null )
+                {
+                    ProblemDescriptor[] descriptors =
+                        verifyAnnotationDeclaredCorrectly( parameter, annotation, manager );
+                    if( descriptors != null )
+                    {
+                        problems.addAll( asList( descriptors ) );
+                    }
+                }
+            }
+
+            return problems.toArray( new ProblemDescriptor[problems.size()] );
+        }
+        else
+        {
+            List<ProblemDescriptor> problems = new LinkedList<ProblemDescriptor>();
+            for( PsiParameter parameter : parameters )
+            {
+                PsiAnnotation annotationToCheck = getAnnotationToCheck( parameter );
+                if( annotationToCheck != null )
+                {
+                    String message = getInjectionAnnotationValidDeclarationMessage();
+                    AbstractFix removeAnnotationFix = createRemoveAnnotationFix( annotationToCheck );
+                    ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(
+                        annotationToCheck, message, removeAnnotationFix, GENERIC_ERROR_OR_WARNING
+                    );
+                    problems.add( problemDescriptor );
+                }
+            }
+
+            return problems.toArray( new ProblemDescriptor[problems.size()] );
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/common/inspections/AbstractInjectionAnnotationDeclarationOnFieldInspection.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/common/inspections/AbstractInjectionAnnotationDeclarationOnFieldInspection.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/common/inspections/AbstractInjectionAnnotationDeclarationOnFieldInspection.java
new file mode 100644
index 0000000..88b3e24
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/common/inspections/AbstractInjectionAnnotationDeclarationOnFieldInspection.java
@@ -0,0 +1,138 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.injections.common.inspections;
+
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiField;
+import com.intellij.psi.PsiModifierList;
+import com.intellij.psi.PsiVariable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractFix;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractInspection;
+
+import static com.intellij.codeInsight.AnnotationUtil.findAnnotation;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public abstract class AbstractInjectionAnnotationDeclarationOnFieldInspection extends AbstractInspection
+{
+    /**
+     * @return Remove annotation message fix.
+     * @since 0.1
+     */
+    @NotNull
+    protected abstract String getRemoveAnnotationMessageFix();
+
+    /**
+     * @return Annotation to check qualified name.
+     * @since 0.1
+     */
+    @NotNull
+    protected abstract String getAnnotationToCheckQualifiedName();
+
+    /**
+     * Verified that {@link #getAnnotationToCheck(com.intellij.psi.PsiVariable)} is declared correctly.
+     *
+     * @param psiVariable       Variable to check. This could be class field member or constructor parameter.
+     * @param annotationToCheck annotation declared at variable to check.
+     * @param manager           Inspection manager to use to create problem descriptor.
+     * @return {@code null} if annotation is declared correctly, otherwise an array of problem descriptor.
+     * @since 0.1
+     */
+    @Nullable
+    protected abstract ProblemDescriptor[] verifyAnnotationDeclaredCorrectly( @NotNull PsiVariable psiVariable,
+                                                                              @NotNull PsiAnnotation annotationToCheck,
+                                                                              @NotNull InspectionManager manager );
+
+    @Override
+    public final ProblemDescriptor[] checkField( @NotNull PsiField field,
+                                                 @NotNull InspectionManager manager,
+                                                 boolean isOnTheFly )
+    {
+        PsiAnnotation annotationToCheck = getAnnotationToCheck( field );
+        if( annotationToCheck == null )
+        {
+            return null;
+        }
+
+        PsiModifierList modifierList = field.getModifierList();
+        if( modifierList != null )
+        {
+            if( modifierList.hasModifierProperty( com.intellij.psi.PsiModifier.STATIC ) )
+            {
+                String message = getInjectionAnnotationValidDeclarationMessage();
+                AbstractFix removeAnnotationFix = createRemoveAnnotationFix( annotationToCheck );
+                ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(
+                    annotationToCheck, message, removeAnnotationFix, com.intellij.codeInspection.ProblemHighlightType.GENERIC_ERROR_OR_WARNING
+                );
+
+                return new ProblemDescriptor[]{ problemDescriptor };
+            }
+        }
+
+        return verifyAnnotationDeclaredCorrectly( field, annotationToCheck, manager );
+    }
+
+    /**
+     * @param variable variable to check.
+     * @return Annotation to check.
+     * @see #getAnnotationToCheckQualifiedName()
+     * @since 0.1
+     */
+    @Nullable
+    protected final PsiAnnotation getAnnotationToCheck( @NotNull PsiVariable variable )
+    {
+        String annotationQualifiedName = getAnnotationToCheckQualifiedName();
+        return findAnnotation( variable, annotationQualifiedName );
+    }
+
+    @NotNull protected String getInjectionAnnotationValidDeclarationMessage()
+    {
+        String annotationQualifiedName = getAnnotationToCheckQualifiedName();
+        return org.apache.zest.ide.plugin.idea.common.resource.Qi4jResourceBundle.message( "abstract.injection.annotation.declaration.inspection.error.annotation.not.declared.correctly",
+                                                                                    annotationQualifiedName );
+    }
+
+    @NotNull
+    protected final AbstractFix createRemoveAnnotationFix( @NotNull PsiAnnotation annotationToRemove )
+    {
+        String fixMessage = getRemoveAnnotationMessageFix();
+        return new RemoveAnnotationFix( fixMessage, annotationToRemove );
+    }
+
+    private static class RemoveAnnotationFix extends AbstractFix
+    {
+        private final PsiAnnotation annotationToRemove;
+
+        public RemoveAnnotationFix( @NotNull String fixMessage, @NotNull PsiAnnotation annotationToRemove )
+        {
+            super( fixMessage );
+            this.annotationToRemove = annotationToRemove;
+        }
+
+        public final void applyFix( @NotNull Project project, @NotNull ProblemDescriptor descriptor )
+        {
+            annotationToRemove.delete();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/common/Qi4jInvocationAnnotationConstants.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/common/Qi4jInvocationAnnotationConstants.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/common/Qi4jInvocationAnnotationConstants.java
new file mode 100644
index 0000000..c2004c6
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/common/Qi4jInvocationAnnotationConstants.java
@@ -0,0 +1,30 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.injections.invocation.common;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class Qi4jInvocationAnnotationConstants
+{
+    public static final String QUALIFIED_NAME_INVOCATION_ANNOTATION = "org.qi4j.api.injection.scope.Invocation";
+
+    private Qi4jInvocationAnnotationConstants()
+    {
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/common/Qi4jInvocationAnnotationUtil.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/common/Qi4jInvocationAnnotationUtil.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/common/Qi4jInvocationAnnotationUtil.java
new file mode 100644
index 0000000..c7ef6da
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/common/Qi4jInvocationAnnotationUtil.java
@@ -0,0 +1,127 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.injections.invocation.common;
+
+import com.intellij.psi.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static com.intellij.codeInsight.AnnotationUtil.findAnnotation;
+import static com.intellij.psi.PsiModifier.STATIC;
+import static org.apache.zest.ide.plugin.idea.common.psi.PsiClassUtil.getPSIClass;
+import static org.apache.zest.ide.plugin.idea.injections.invocation.common.Qi4jInvocationAnnotationConstants.QUALIFIED_NAME_INVOCATION_ANNOTATION;
+import static org.apache.zest.ide.plugin.idea.injections.invocation.common.Qi4jInvocationAnnotationUtil.InvocationAnnotationDeclarationValidationResult.*;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationUtil.isInjecteableByStructureAnnotation;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class Qi4jInvocationAnnotationUtil
+{
+    /**
+     * Returns {@code @Invocation} annotation if exists.
+     *
+     * @param modifierListOwner modifier list owner to process.
+     * @return {@code @Invocation} annotation if exists, {@code null} otherwise.
+     * @since 0.1
+     */
+    @Nullable
+    public static PsiAnnotation getInvocationAnnotation( @NotNull PsiModifierListOwner modifierListOwner )
+    {
+        return findAnnotation( modifierListOwner, QUALIFIED_NAME_INVOCATION_ANNOTATION );
+    }
+
+    /**
+     * @param psiClass psi class to check.
+     * @return {@code true} if the specified psiClass is injectable by invocation annotation, {@code false} otherwise.
+     */
+    public static boolean isInjectableByInvocationAnnotation( @NotNull PsiClass psiClass )
+    {
+        if( psiClass.isAnnotationType() )
+        {
+            return true;
+        }
+
+        String classQualifiedName = psiClass.getQualifiedName();
+        return "java.lang.reflect.Method".equals( classQualifiedName ) ||
+               "java.lang.reflect.AnnotatedElement".equals( classQualifiedName );
+    }
+
+    /**
+     * Validates whether the variable has {@code @Invocation} annotation declared correctly.
+     *
+     * @param variable variable to check.
+     * @return Look at {@link InvocationAnnotationDeclarationValidationResult}.
+     * @since 0.1
+     */
+    @NotNull
+    public static InvocationAnnotationDeclarationValidationResult isValidInvocationAnnotationDeclaration(
+        @NotNull PsiVariable variable )
+    {
+        PsiAnnotation invocationAnnotation = getInvocationAnnotation( variable );
+        if( invocationAnnotation == null )
+        {
+            return invalidInvocationAnnotationNotDeclared;
+        }
+
+        PsiModifierList modifierList = variable.getModifierList();
+        if( modifierList != null )
+        {
+            if( modifierList.hasModifierProperty( STATIC ) )
+            {
+                return invalidDeclaredOnStaticVariable;
+            }
+        }
+
+        // TODO: Check whether variable is either an instance of java.lang.reflect.Method or
+        // java.lang.reflect.AnnotatedElement or Annotation
+        PsiTypeElement typeElement = variable.getTypeElement();
+        if( typeElement != null )
+        {
+            PsiClass psiClass = getPSIClass( typeElement );
+            if( psiClass != null )
+            {
+                if( !isInjectableByInvocationAnnotation( psiClass ) )
+                {
+                    // Can't be type that is injected by @Structure
+                    if( isInjecteableByStructureAnnotation( variable ) )
+                    {
+                        return invalidTypeIsInjectedViaStructureAnnotation;
+                    }
+
+                    return invalidType;
+                }
+            }
+        }
+
+        return valid;
+    }
+
+    public enum InvocationAnnotationDeclarationValidationResult
+    {
+        invalidInvocationAnnotationNotDeclared,
+        invalidDeclaredOnStaticVariable,
+        invalidTypeIsInjectedViaStructureAnnotation,
+        invalidType,
+        valid,
+    }
+
+    private Qi4jInvocationAnnotationUtil()
+    {
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/inspections/InvocationAnnotationDeclaredCorrectlyInspection.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/inspections/InvocationAnnotationDeclaredCorrectlyInspection.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/inspections/InvocationAnnotationDeclaredCorrectlyInspection.java
new file mode 100644
index 0000000..57e9b60
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/inspections/InvocationAnnotationDeclaredCorrectlyInspection.java
@@ -0,0 +1,119 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.injections.invocation.inspections;
+
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.LocalQuickFix;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiVariable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.apache.zest.ide.plugin.idea.injections.common.inspections.AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection;
+import org.apache.zest.ide.plugin.idea.injections.structure.common.ReplaceWithStructureAnnotation;
+
+import static com.intellij.codeInspection.ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
+import static org.apache.zest.ide.plugin.idea.common.resource.Qi4jResourceBundle.message;
+import static org.apache.zest.ide.plugin.idea.injections.invocation.common.Qi4jInvocationAnnotationConstants.QUALIFIED_NAME_INVOCATION_ANNOTATION;
+import static org.apache.zest.ide.plugin.idea.injections.invocation.common.Qi4jInvocationAnnotationUtil.InvocationAnnotationDeclarationValidationResult;
+import static org.apache.zest.ide.plugin.idea.injections.invocation.common.Qi4jInvocationAnnotationUtil.isValidInvocationAnnotationDeclaration;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationUtil.getStructureAnnotation;
+
+/**
+ * {@code InvocationAnnotationDeclaredCorrectlyInspection} validates {@code @Invocation} injection annotation
+ * declaration.
+ *
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public class InvocationAnnotationDeclaredCorrectlyInspection
+    extends AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection
+{
+    @NotNull
+    protected final String resourceBundlePrefixId()
+    {
+        return "injections.invocation.annotation.declared.correctly";
+    }
+
+    @NotNull
+    public final String getShortName()
+    {
+        return "InvocationAnnotationDeclaredCorrectlyInspection";
+    }
+
+    @NotNull
+    protected final String getRemoveAnnotationMessageFix()
+    {
+        return message( "injections.invocation.annotation.declared.correctly.fix.remove.annotation" );
+    }
+
+    @NotNull
+    protected final String getAnnotationToCheckQualifiedName()
+    {
+        return QUALIFIED_NAME_INVOCATION_ANNOTATION;
+    }
+
+    @Nullable
+    protected final ProblemDescriptor[] verifyAnnotationDeclaredCorrectly( @NotNull PsiVariable psiVariable,
+                                                                           @NotNull PsiAnnotation invocationAnnotation,
+                                                                           @NotNull InspectionManager manager )
+    {
+        LocalQuickFix fix = null;
+        String message = null;
+
+        String variableTypeQualifiedName = psiVariable.getType().getCanonicalText();
+
+        InvocationAnnotationDeclarationValidationResult validationResult =
+            isValidInvocationAnnotationDeclaration( psiVariable );
+        switch( validationResult )
+        {
+        case invalidTypeIsInjectedViaStructureAnnotation:
+            if( getStructureAnnotation( psiVariable ) == null )
+            {
+                fix = new ReplaceWithStructureAnnotation(
+                    message( "injections.invocation.annotation.declared.correctly.fix.replace.with.structure.annotation" ),
+                    invocationAnnotation );
+            }
+            message = message(
+                "injections.invocation.annotation.declared.correctly.error.type.is.injected.by.structure",
+                variableTypeQualifiedName
+            );
+            break;
+
+        case invalidType:
+            message = message( "injections.invocation.annotation.declared.correctly.error.type.is.not.injectable",
+                               variableTypeQualifiedName );
+            break;
+        }
+
+        // If it's not an error, return null
+        if( message == null )
+        {
+            return null;
+        }
+
+        // If Fix not defined, by default we remove it.
+        if( fix == null )
+        {
+            fix = createRemoveAnnotationFix( invocationAnnotation );
+        }
+
+        ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(
+            invocationAnnotation, message, fix, GENERIC_ERROR_OR_WARNING );
+        return new ProblemDescriptor[]{ problemDescriptor };
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/common/Qi4jServiceAnnotationConstants.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/common/Qi4jServiceAnnotationConstants.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/common/Qi4jServiceAnnotationConstants.java
new file mode 100644
index 0000000..4ab8602
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/common/Qi4jServiceAnnotationConstants.java
@@ -0,0 +1,30 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.injections.service.common;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class Qi4jServiceAnnotationConstants
+{
+    public static final String QUALIFIED_NAME_SERVICE_ANNOTATION = "org.qi4j.api.injection.scope.Service";
+
+    private Qi4jServiceAnnotationConstants()
+    {
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/common/Qi4jServiceAnnotationUtil.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/common/Qi4jServiceAnnotationUtil.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/common/Qi4jServiceAnnotationUtil.java
new file mode 100644
index 0000000..824466c
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/common/Qi4jServiceAnnotationUtil.java
@@ -0,0 +1,97 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.injections.service.common;
+
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiModifierList;
+import com.intellij.psi.PsiModifierListOwner;
+import com.intellij.psi.PsiVariable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static com.intellij.codeInsight.AnnotationUtil.findAnnotation;
+import static com.intellij.psi.PsiModifier.STATIC;
+import static org.apache.zest.ide.plugin.idea.injections.service.common.Qi4jServiceAnnotationConstants.QUALIFIED_NAME_SERVICE_ANNOTATION;
+import static org.apache.zest.ide.plugin.idea.injections.service.common.Qi4jServiceAnnotationUtil.ServiceAnnotationDeclarationValidationResult.*;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationUtil.isInjecteableByStructureAnnotation;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class Qi4jServiceAnnotationUtil
+{
+    /**
+     * Returns {@code @Service} annotation if exists.
+     *
+     * @param modifierListOwner modifier list owner to process.
+     * @return {@code @Service} annotation if exists, {@code null} otherwise.
+     * @since 0.1
+     */
+    @Nullable
+    public static PsiAnnotation getServiceAnnotation( @NotNull PsiModifierListOwner modifierListOwner )
+    {
+        return findAnnotation( modifierListOwner, QUALIFIED_NAME_SERVICE_ANNOTATION );
+    }
+
+    /**
+     * Validates whether the variable has {@code @Service} annotation declared correctly.
+     *
+     * @param variable variable to check.
+     * @return Look at {@link ServiceAnnotationDeclarationValidationResult}.
+     * @since 0.1
+     */
+    @NotNull
+    public static ServiceAnnotationDeclarationValidationResult isValidServiceAnnotationDeclaration(
+        @NotNull PsiVariable variable )
+    {
+        PsiAnnotation serviceAnnotation = getServiceAnnotation( variable );
+        if( serviceAnnotation == null )
+        {
+            return invalidServiceAnnotationNotDeclared;
+        }
+
+        PsiModifierList modifierList = variable.getModifierList();
+        if( modifierList != null )
+        {
+            if( modifierList.hasModifierProperty( STATIC ) )
+            {
+                return invalidDeclaredOnStaticVariable;
+            }
+        }
+
+        // Can't be type that is injected by @Structure
+        if( isInjecteableByStructureAnnotation( variable ) )
+        {
+            return invalidTypeIsInjectedViaStructureAnnotation;
+        }
+
+        return valid;
+    }
+
+    public enum ServiceAnnotationDeclarationValidationResult
+    {
+        invalidServiceAnnotationNotDeclared,
+        invalidDeclaredOnStaticVariable,
+        invalidTypeIsInjectedViaStructureAnnotation,
+        valid,
+    }
+
+    private Qi4jServiceAnnotationUtil()
+    {
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/inspections/ServiceAnnotationDeclaredCorrectlyInspection.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/inspections/ServiceAnnotationDeclaredCorrectlyInspection.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/inspections/ServiceAnnotationDeclaredCorrectlyInspection.java
new file mode 100644
index 0000000..be3a82b
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/inspections/ServiceAnnotationDeclaredCorrectlyInspection.java
@@ -0,0 +1,110 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.injections.service.inspections;
+
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.LocalQuickFix;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiVariable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.apache.zest.ide.plugin.idea.injections.common.inspections.AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection;
+import org.apache.zest.ide.plugin.idea.injections.structure.common.ReplaceWithStructureAnnotation;
+
+import static com.intellij.codeInspection.ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
+import static org.apache.zest.ide.plugin.idea.common.resource.Qi4jResourceBundle.message;
+import static org.apache.zest.ide.plugin.idea.injections.service.common.Qi4jServiceAnnotationConstants.QUALIFIED_NAME_SERVICE_ANNOTATION;
+import static org.apache.zest.ide.plugin.idea.injections.service.common.Qi4jServiceAnnotationUtil.ServiceAnnotationDeclarationValidationResult;
+import static org.apache.zest.ide.plugin.idea.injections.service.common.Qi4jServiceAnnotationUtil.isValidServiceAnnotationDeclaration;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationUtil.getStructureAnnotation;
+
+/**
+ * {@code ServiceAnnotationDeclaredCorrectly} validates {@code @Service} injection annotation declaration.
+ *
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public class ServiceAnnotationDeclaredCorrectlyInspection
+    extends AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection
+{
+    @NotNull
+    protected final String resourceBundlePrefixId()
+    {
+        return "injections.service.annotation.declared.correctly";
+    }
+
+    @NotNull
+    public final String getShortName()
+    {
+        return "ServiceAnnotationDeclaredCorrectlyInspection";
+    }
+
+    @NotNull
+    protected final String getRemoveAnnotationMessageFix()
+    {
+        return message( "injections.service.annotation.declared.correctly.fix.remove.annotation" );
+    }
+
+    @NotNull
+    protected final String getAnnotationToCheckQualifiedName()
+    {
+        return QUALIFIED_NAME_SERVICE_ANNOTATION;
+    }
+
+    @Nullable
+    protected final ProblemDescriptor[] verifyAnnotationDeclaredCorrectly( @NotNull PsiVariable psiVariable,
+                                                                           @NotNull PsiAnnotation serviceAnnotation,
+                                                                           @NotNull InspectionManager manager )
+    {
+        ServiceAnnotationDeclarationValidationResult annotationCheck =
+            isValidServiceAnnotationDeclaration( psiVariable );
+        String message = null;
+        LocalQuickFix fix = null;
+        switch( annotationCheck )
+        {
+        case invalidTypeIsInjectedViaStructureAnnotation:
+            if( getStructureAnnotation( psiVariable ) == null )
+            {
+                fix = new ReplaceWithStructureAnnotation(
+                    message( "injections.service.annotation.declared.correctly.fix.replace.with.structure.annotation" ),
+                    serviceAnnotation );
+            }
+            message = message(
+                "injections.service.annotation.declared.correctly.error.type.is.injected.by.structure",
+                psiVariable.getType().getCanonicalText()
+            );
+            break;
+        }
+
+        // If it's not an error, return null
+        if( message == null )
+        {
+            return null;
+        }
+
+        // Default behavior to remove @Service annotation
+        if( fix == null )
+        {
+            fix = createRemoveAnnotationFix( serviceAnnotation );
+        }
+
+        ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(
+            serviceAnnotation, message, fix, GENERIC_ERROR_OR_WARNING );
+        return new ProblemDescriptor[]{ problemDescriptor };
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/Qi4jStructureAnnotationConstants.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/Qi4jStructureAnnotationConstants.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/Qi4jStructureAnnotationConstants.java
new file mode 100644
index 0000000..9635ad4
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/Qi4jStructureAnnotationConstants.java
@@ -0,0 +1,51 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.injections.structure.common;
+
+import static java.util.Arrays.sort;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class Qi4jStructureAnnotationConstants
+{
+    public static final String QUALIFIED_NAME_STRUCTURE_ANNOTATION = "org.qi4j.api.injection.scope.Structure";
+
+    public static final String[] VALID_STRUCTURE_INJECTION_TYPE;
+
+    static
+    {
+        VALID_STRUCTURE_INJECTION_TYPE = new String[]
+            {
+                "org.qi4j.composite.CompositeBuilderFactory",
+                "org.qi4j.object.ObjectBuilderFactory",
+                "org.qi4j.entity.UnitOfWorkFactory",
+                "org.qi4j.service.ServiceFinder",
+                "org.qi4j.structure.Module",
+                "org.qi4j.structure.Layer",
+                "org.qi4j.structure.Application",
+                "org.qi4j.Qi4j",
+                "org.qi4j.spi.Qi4jSPI"
+            };
+        sort( VALID_STRUCTURE_INJECTION_TYPE );
+    }
+
+    private Qi4jStructureAnnotationConstants()
+    {
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/Qi4jStructureAnnotationUtil.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/Qi4jStructureAnnotationUtil.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/Qi4jStructureAnnotationUtil.java
new file mode 100644
index 0000000..da54dd9
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/Qi4jStructureAnnotationUtil.java
@@ -0,0 +1,122 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.injections.structure.common;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static com.intellij.codeInsight.AnnotationUtil.findAnnotation;
+import static com.intellij.psi.PsiModifier.STATIC;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationConstants.QUALIFIED_NAME_STRUCTURE_ANNOTATION;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationConstants.VALID_STRUCTURE_INJECTION_TYPE;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationUtil.StructureAnnotationDeclarationValidationResult.*;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class Qi4jStructureAnnotationUtil
+{
+    /**
+     * Returns {@code Structure} annotation if exists.
+     *
+     * @param modifierListOwner Modifier list owner.
+     * @return @Structure annotation if exists, {@code null} otherwise.
+     * @since 0.1
+     */
+    @Nullable
+    public static PsiAnnotation getStructureAnnotation( @NotNull PsiModifierListOwner modifierListOwner )
+    {
+        return findAnnotation( modifierListOwner, QUALIFIED_NAME_STRUCTURE_ANNOTATION );
+    }
+
+    /**
+     * Create structure annotation.
+     *
+     * @param project project to create structure annotation.
+     * @param context the context to create structure annotation.
+     * @return @Structure annotation.
+     */
+    @NotNull
+    public static PsiAnnotation createStructureAnnotation( @NotNull Project project,
+                                                           @NotNull PsiElement context )
+    {
+        JavaPsiFacade psiFacade = JavaPsiFacade.getInstance( project );
+        PsiElementFactory factory = psiFacade.getElementFactory();
+        return factory.createAnnotationFromText( "@" + QUALIFIED_NAME_STRUCTURE_ANNOTATION, context );
+    }
+
+    /**
+     * @param variable variable to check.
+     * @return Look at {@link StructureAnnotationDeclarationValidationResult}.
+     * @since 0.1
+     */
+    @NotNull
+    public static StructureAnnotationDeclarationValidationResult validateStructureAnnotationDeclaration(
+        @NotNull PsiVariable variable )
+    {
+        PsiAnnotation structureAnnotation = getStructureAnnotation( variable );
+        if( structureAnnotation == null )
+        {
+            return invalidStructureAnnotationNotDeclared;
+        }
+
+        PsiModifierList modifierList = variable.getModifierList();
+        if( modifierList != null )
+        {
+            if( modifierList.hasModifierProperty( STATIC ) )
+            {
+                return invalidDeclaredOnStaticVariable;
+            }
+        }
+
+        if( !isInjecteableByStructureAnnotation( variable ) )
+        {
+            return invalidInjectionType;
+        }
+
+        return valid;
+    }
+
+    /**
+     * Returns a {@code boolean} indicator whether variable type is injectable by @Structure annotation.
+     *
+     * @param variable variable to check.
+     * @return {@code true} if variable type is injecteable by @Structure annotation.
+     * @since 0.1
+     */
+    public static boolean isInjecteableByStructureAnnotation( @NotNull PsiVariable variable )
+    {
+        PsiType type = variable.getType();
+        String fieldClassQualifiedName = type.getCanonicalText();
+        return binarySearch( VALID_STRUCTURE_INJECTION_TYPE, fieldClassQualifiedName ) > -1;
+    }
+
+    private Qi4jStructureAnnotationUtil()
+    {
+    }
+
+    public enum StructureAnnotationDeclarationValidationResult
+    {
+        invalidStructureAnnotationNotDeclared,
+        invalidDeclaredOnStaticVariable,
+        invalidInjectionType,
+        valid,
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/ReplaceWithStructureAnnotation.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/ReplaceWithStructureAnnotation.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/ReplaceWithStructureAnnotation.java
new file mode 100644
index 0000000..3cd6fb6
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/ReplaceWithStructureAnnotation.java
@@ -0,0 +1,47 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.injections.structure.common;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiAnnotation;
+import org.jetbrains.annotations.NotNull;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractFix;
+
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationUtil.createStructureAnnotation;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class ReplaceWithStructureAnnotation extends AbstractFix
+{
+    private final PsiAnnotation annotation;
+
+    public ReplaceWithStructureAnnotation( @NotNull String fixMessage,
+                                           @NotNull PsiAnnotation annotationToReplace )
+    {
+        super( fixMessage );
+        this.annotation = annotationToReplace;
+    }
+
+    public final void applyFix( @NotNull Project project, @NotNull ProblemDescriptor descriptor )
+    {
+        PsiAnnotation structureAnnotation = createStructureAnnotation( project, annotation );
+        annotation.replace( structureAnnotation );
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/inspections/StructureAnnotationDeclaredCorrectlyInspection.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/inspections/StructureAnnotationDeclaredCorrectlyInspection.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/inspections/StructureAnnotationDeclaredCorrectlyInspection.java
new file mode 100644
index 0000000..7baea38
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/inspections/StructureAnnotationDeclaredCorrectlyInspection.java
@@ -0,0 +1,90 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.injections.structure.inspections;
+
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiVariable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractFix;
+import org.apache.zest.ide.plugin.idea.injections.common.inspections.AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection;
+
+import static com.intellij.codeInspection.ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
+import static org.apache.zest.ide.plugin.idea.common.resource.Qi4jResourceBundle.message;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationConstants.QUALIFIED_NAME_STRUCTURE_ANNOTATION;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationUtil.StructureAnnotationDeclarationValidationResult;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationUtil.validateStructureAnnotationDeclaration;
+
+/**
+ * {@code StructureAnnotationUsedCorrectly} validates {@code @Structure} injection annotation declaration.
+ *
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public class StructureAnnotationDeclaredCorrectlyInspection
+    extends AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection
+{
+    @NotNull
+    protected final String resourceBundlePrefixId()
+    {
+        return "injections.structure.annotation.declared.correctly";
+    }
+
+    @NotNull
+    public final String getShortName()
+    {
+        return "StructureAnnotationDeclaredCorrectlyInspection";
+    }
+
+    @NotNull
+    protected final String getRemoveAnnotationMessageFix()
+    {
+        return message( "injections.structure.annotation.declared.correctly.fix.remove.annotation" );
+    }
+
+    @NotNull
+    protected final String getAnnotationToCheckQualifiedName()
+    {
+        return QUALIFIED_NAME_STRUCTURE_ANNOTATION;
+    }
+
+    @Nullable
+    protected final ProblemDescriptor[] verifyAnnotationDeclaredCorrectly( @NotNull PsiVariable psiVariable,
+                                                                           @NotNull PsiAnnotation structureAnnotation,
+                                                                           @NotNull InspectionManager manager )
+    {
+        StructureAnnotationDeclarationValidationResult annotationCheck =
+            validateStructureAnnotationDeclaration( psiVariable );
+        switch( annotationCheck )
+        {
+        case invalidInjectionType:
+            String message = message(
+                "injections.structure.annotation.declared.correctly.error.invalid.injection.type",
+                psiVariable.getType().getCanonicalText()
+            );
+            AbstractFix removeStructureAnnotationFix = createRemoveAnnotationFix( structureAnnotation );
+            ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(
+                structureAnnotation, message, removeStructureAnnotationFix, GENERIC_ERROR_OR_WARNING
+            );
+            return new ProblemDescriptor[]{ problemDescriptor };
+        }
+
+        return null;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/common/Qi4jMixinConstants.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/common/Qi4jMixinConstants.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/common/Qi4jMixinConstants.java
new file mode 100644
index 0000000..e2f02df
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/common/Qi4jMixinConstants.java
@@ -0,0 +1,30 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.mixins.common;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class Qi4jMixinConstants
+{
+    public static final String QUALIFIED_NAME_MIXINS = "org.qi4j.api.mixin.Mixins";
+
+    private Qi4jMixinConstants()
+    {
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/common/Qi4jMixinUtil.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/common/Qi4jMixinUtil.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/common/Qi4jMixinUtil.java
new file mode 100644
index 0000000..e8100bd
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/common/Qi4jMixinUtil.java
@@ -0,0 +1,194 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.mixins.common;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.JavaCodeStyleManager;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Set;
+
+import static com.intellij.codeInsight.AnnotationUtil.findAnnotation;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.emptySet;
+import static org.apache.zest.ide.plugin.idea.common.psi.PsiAnnotationUtil.getAnnotationDefaultParameterValue;
+import static org.apache.zest.ide.plugin.idea.common.psi.PsiAnnotationUtil.getClassReference;
+import static org.apache.zest.ide.plugin.idea.common.psi.PsiClassUtil.getExtendsDeep;
+import static org.apache.zest.ide.plugin.idea.common.psi.PsiClassUtil.getPSIClass;
+import static org.apache.zest.ide.plugin.idea.concerns.common.Qi4jConcernUtil.isAConcern;
+import static org.apache.zest.ide.plugin.idea.mixins.common.Qi4jMixinConstants.QUALIFIED_NAME_MIXINS;
+import static org.apache.zest.ide.plugin.idea.sideEffects.common.Qi4jSideEffectUtil.isASideEffect;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class Qi4jMixinUtil
+{
+    /**
+     * Get all valid mixin types of given the {@code psiClass} argument.
+     *
+     * @param psiClass The psi class to check.
+     * @return all vlaid mixin types of the given {@code psiClass} argument.
+     * @since 0.1
+     */
+    @NotNull
+    public static Set<PsiClass> getAllValidMixinTypes( @NotNull PsiClass psiClass )
+    {
+        PsiAnnotation mixinsAnnotation = getMixinsAnnotation( psiClass );
+        if( mixinsAnnotation == null )
+        {
+            return emptySet();
+        }
+
+        Set<PsiClass> validMixinsType = getExtendsDeep( psiClass );
+        validMixinsType.add( psiClass );
+        return validMixinsType;
+    }
+
+    @NotNull
+    public static List<PsiAnnotationMemberValue> getMixinsAnnotationValue( @NotNull PsiClass psiClass )
+    {
+        return getMixinsAnnotationValue( getMixinsAnnotation( psiClass ) );
+    }
+
+    @NotNull
+    public static List<PsiAnnotationMemberValue> getMixinsAnnotationValue( @Nullable PsiAnnotation mixinsAnnotation )
+    {
+        if( mixinsAnnotation == null )
+        {
+            return emptyList();
+        }
+
+        String mixinsQualifiedName = mixinsAnnotation.getQualifiedName();
+        if( !QUALIFIED_NAME_MIXINS.equals( mixinsQualifiedName ) )
+        {
+            return emptyList();
+        }
+
+        return getAnnotationDefaultParameterValue( mixinsAnnotation );
+    }
+
+    @Nullable
+    public static PsiAnnotation getMixinsAnnotation( PsiElement element )
+    {
+        PsiClass psiClass = getPSIClass( element );
+        if( psiClass == null )
+        {
+            return null;
+        }
+
+        return findAnnotation( psiClass, QUALIFIED_NAME_MIXINS );
+    }
+
+    @NotNull
+    public static PsiAnnotation addOrReplaceMixinAnnotation( @NotNull PsiModifierListOwner modifierListOwner,
+                                                             @NotNull PsiClass mixinClassToAdd )
+    {
+        Project project = modifierListOwner.getProject();
+        JavaPsiFacade psiFacade = JavaPsiFacade.getInstance( project );
+        PsiElementFactory factory = psiFacade.getElementFactory();
+        PsiAnnotation existingMixinsAnnotation = findAnnotation( modifierListOwner, QUALIFIED_NAME_MIXINS );
+
+        boolean isReplace = false;
+        PsiAnnotation newMixinsAnnotation;
+        if( existingMixinsAnnotation != null )
+        {
+            // Check duplicate
+            List<PsiAnnotationMemberValue> mixinsValues = getMixinsAnnotationValue( existingMixinsAnnotation );
+            for( PsiAnnotationMemberValue mixinValue : mixinsValues )
+            {
+                PsiJavaCodeReferenceElement mixinClassReference = getMixinClassReference( mixinValue );
+                if( mixinClassReference == null )
+                {
+                    continue;
+                }
+
+                PsiElement mixinClass = mixinClassReference.resolve();
+                if( mixinClassToAdd.equals( mixinClass ) )
+                {
+                    return existingMixinsAnnotation;
+                }
+            }
+
+            isReplace = true;
+        }
+
+        String mixinsAnnotationText = createMixinsAnnotationText( existingMixinsAnnotation, mixinClassToAdd );
+        newMixinsAnnotation = factory.createAnnotationFromText( mixinsAnnotationText, modifierListOwner );
+
+        if( isReplace )
+        {
+            // Replace @Mixins instead
+            existingMixinsAnnotation.replace( newMixinsAnnotation );
+        }
+        else
+        {
+            // @Mixins doesn't exists, add it as first child
+            PsiModifierList modifierList = modifierListOwner.getModifierList();
+            modifierList.addBefore( newMixinsAnnotation, modifierList.getFirstChild() );
+        }
+
+        // Shorten all class references if possible
+        JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance( project );
+        codeStyleManager.shortenClassReferences( newMixinsAnnotation );
+
+        return newMixinsAnnotation;
+    }
+
+    @NotNull
+    private static String createMixinsAnnotationText( @Nullable PsiAnnotation mixinsAnnotationBase,
+                                                      @NotNull PsiClass mixinClassToAdd )
+    {
+        StringBuilder annotationTextBuilder = new StringBuilder();
+        annotationTextBuilder.append( "@" ).append( QUALIFIED_NAME_MIXINS ).append( "( {" );
+        List<PsiAnnotationMemberValue> mixinsValues = getMixinsAnnotationValue( mixinsAnnotationBase );
+        for( PsiAnnotationMemberValue mixinValue : mixinsValues )
+        {
+            annotationTextBuilder.append( mixinValue.getText() ).append( ", " );
+        }
+        annotationTextBuilder.append( mixinClassToAdd.getQualifiedName() ).append( ".class" );
+        annotationTextBuilder.append( "} )" );
+
+        return annotationTextBuilder.toString();
+    }
+
+
+    @Nullable
+    public static PsiJavaCodeReferenceElement getMixinClassReference( @NotNull PsiAnnotationMemberValue value )
+    {
+        return getClassReference( value );
+    }
+
+    /**
+     * Validate whether psiClass is a mixin.
+     *
+     * @param psiClass psi class to check.
+     * @return {@code true} if psiClass is a mixin, {@code false} otherwise.
+     */
+    public static boolean isAMixin( @NotNull PsiClass psiClass )
+    {
+        return !( psiClass.isInterface() || isAConcern( psiClass ) || isASideEffect( psiClass ) );
+    }
+
+    private Qi4jMixinUtil()
+    {
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/inspections/MixinImplementsMixinType.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/inspections/MixinImplementsMixinType.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/inspections/MixinImplementsMixinType.java
new file mode 100644
index 0000000..f03722f
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/inspections/MixinImplementsMixinType.java
@@ -0,0 +1,188 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.mixins.inspections;
+
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiAnnotationMemberValue;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiJavaCodeReferenceElement;
+import org.jetbrains.annotations.NotNull;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractFix;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractInspection;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import static com.intellij.codeInspection.ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
+import static org.apache.zest.ide.plugin.idea.common.resource.Qi4jResourceBundle.message;
+import static org.apache.zest.ide.plugin.idea.concerns.common.Qi4jConcernUtil.isAConcern;
+import static org.apache.zest.ide.plugin.idea.mixins.common.Qi4jMixinUtil.*;
+import static org.apache.zest.ide.plugin.idea.sideEffects.common.Qi4jSideEffectUtil.isASideEffect;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class MixinImplementsMixinType extends AbstractInspection
+{
+    @NotNull
+    protected final String resourceBundlePrefixId()
+    {
+        return "mixin.implements.mixin.type";
+    }
+
+    @NotNull
+    public final String getShortName()
+    {
+        return "MixinImplementsMixinType";
+    }
+
+    @Override
+    public final ProblemDescriptor[] checkClass( @NotNull PsiClass psiClass,
+                                                 @NotNull InspectionManager manager,
+                                                 boolean isOnTheFly )
+    {
+        // If psiClass is not an interface, ignore
+        if( !psiClass.isInterface() )
+        {
+            return null;
+        }
+
+        // If @Mixins annotation is empty, ignore
+        List<PsiAnnotationMemberValue> mixinAnnotationValues = getMixinsAnnotationValue( psiClass );
+        if( mixinAnnotationValues.isEmpty() )
+        {
+            return null;
+        }
+
+        // Get all valid mixin type
+        Set<PsiClass> validMixinsType = getAllValidMixinTypes( psiClass );
+        if( validMixinsType.isEmpty() )
+        {
+            return null;
+        }
+
+        // For each mixin
+        List<ProblemDescriptor> problems = new LinkedList<ProblemDescriptor>();
+        for( PsiAnnotationMemberValue mixinAnnotationValue : mixinAnnotationValues )
+        {
+            PsiJavaCodeReferenceElement mixinClassReference = getMixinClassReference( mixinAnnotationValue );
+
+            // If it's not a class reference, ignore
+            if( mixinClassReference == null )
+            {
+                continue;
+            }
+
+            // If class reference can't be resolved, ignore
+            PsiClass mixinClass = (PsiClass) mixinClassReference.resolve();
+            if( mixinClass == null )
+            {
+                continue;
+            }
+
+            String mixinQualifiedName = mixinClass.getQualifiedName();
+
+            boolean isMixinsDeclarationValid = false;
+            String message = "";
+            if( mixinClass.isInterface() )
+            {
+                // Mixin can't be an interface
+                message = message( "mixin.implements.mixin.type.error.mixin.is.an.interface", mixinQualifiedName );
+            }
+            else if( isAConcern( mixinClass ) )
+            {
+                // Mixin can't be a concern
+                message = message( "mixin.implements.mixin.type.error.mixin.is.a.concern", mixinQualifiedName );
+            }
+            else if( isASideEffect( mixinClass ) )
+            {
+                // Mixin can't be a side effect
+                message = message( "mixin.implements.mixin.type.error.mixin.is.a.side.effect", mixinQualifiedName );
+            }
+            else
+            {
+                // If doesn't implement any mixin type, it's a problem
+                if( !isImplementValidMixinType( mixinClass, validMixinsType ) )
+                {
+                    message = message(
+                        "mixin.implements.mixin.type.error.does.not.implement.any.mixin.type",
+                        mixinQualifiedName,
+                        psiClass.getQualifiedName()
+                    );
+                }
+                else
+                {
+                    isMixinsDeclarationValid = true;
+                }
+            }
+
+            if( !isMixinsDeclarationValid )
+            {
+                ProblemDescriptor problemDescriptor = createProblemDescriptor(
+                    manager, mixinAnnotationValue, mixinClassReference, message );
+                problems.add( problemDescriptor );
+            }
+        }
+
+        return problems.toArray( new ProblemDescriptor[problems.size()] );
+    }
+
+    private boolean isImplementValidMixinType( PsiClass mixinClass, Set<PsiClass> validMixinsType )
+    {
+        for( PsiClass validMixinTypeClass : validMixinsType )
+        {
+            if( mixinClass.isInheritor( validMixinTypeClass, true ) )
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private ProblemDescriptor createProblemDescriptor( @NotNull InspectionManager manager,
+                                                       @NotNull PsiAnnotationMemberValue mixinAnnotationValue,
+                                                       @NotNull PsiJavaCodeReferenceElement mixinClassReference,
+                                                       @NotNull String message )
+    {
+        RemoveInvalidMixinClassReferenceFix fix = new RemoveInvalidMixinClassReferenceFix(
+            mixinAnnotationValue, mixinClassReference
+        );
+        return manager.createProblemDescriptor( mixinAnnotationValue, message, fix, GENERIC_ERROR_OR_WARNING );
+    }
+
+    private static class RemoveInvalidMixinClassReferenceFix extends AbstractFix
+    {
+        private final PsiAnnotationMemberValue mixinClassAnnotationValue;
+
+        public RemoveInvalidMixinClassReferenceFix( @NotNull PsiAnnotationMemberValue mixinClassAnnotationValue,
+                                                    @NotNull PsiJavaCodeReferenceElement mixinClassReference )
+        {
+            super( message( "mixin.implements.mixin.type.fix.remove.class.reference", mixinClassReference.getQualifiedName() ) );
+            this.mixinClassAnnotationValue = mixinClassAnnotationValue;
+        }
+
+        public final void applyFix( @NotNull Project project, @NotNull ProblemDescriptor descriptor )
+        {
+            mixinClassAnnotationValue.delete();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/inspections/MixinsAnnotationDeclaredOnMixinType.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/inspections/MixinsAnnotationDeclaredOnMixinType.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/inspections/MixinsAnnotationDeclaredOnMixinType.java
new file mode 100644
index 0000000..c4ebfde
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/inspections/MixinsAnnotationDeclaredOnMixinType.java
@@ -0,0 +1,90 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.mixins.inspections;
+
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiAnnotationMemberValue;
+import com.intellij.psi.PsiClass;
+import org.jetbrains.annotations.NotNull;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractFix;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractInspection;
+
+import static com.intellij.codeInspection.ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
+import static org.apache.zest.ide.plugin.idea.common.resource.Qi4jResourceBundle.message;
+import static org.apache.zest.ide.plugin.idea.mixins.common.Qi4jMixinUtil.getMixinsAnnotation;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class MixinsAnnotationDeclaredOnMixinType extends AbstractInspection
+{
+    @NotNull
+    public final String getShortName()
+    {
+        return "MixinsAnnotationDeclaredOnMixinType";
+    }
+
+    @NotNull
+    protected final String resourceBundlePrefixId()
+    {
+        return "mixins.annotation.declared.on.mixin.type";
+    }
+
+    @Override
+    public ProblemDescriptor[] checkClass( @NotNull PsiClass psiClass,
+                                           @NotNull InspectionManager manager,
+                                           boolean isOnTheFly )
+    {
+        PsiAnnotation mixinsAnnotation = getMixinsAnnotation( psiClass );
+        if( mixinsAnnotation == null )
+        {
+            return null;
+        }
+
+        if( psiClass.isInterface() )
+        {
+            return null;
+        }
+
+        String message = message( "mixins.annotation.declared.on.mixin.type.error.declared.on.class" );
+        RemoveInvalidMixinClassReferenceFix fix = new RemoveInvalidMixinClassReferenceFix( mixinsAnnotation );
+        ProblemDescriptor problemDescriptor = manager.createProblemDescriptor( mixinsAnnotation, message, fix,
+                                                                               GENERIC_ERROR_OR_WARNING );
+        return new ProblemDescriptor[]{ problemDescriptor };
+
+    }
+
+    private static class RemoveInvalidMixinClassReferenceFix extends AbstractFix
+    {
+        private final PsiAnnotationMemberValue mixinsAnnotation;
+
+        public RemoveInvalidMixinClassReferenceFix( @NotNull PsiAnnotationMemberValue mixinsAnnotation )
+        {
+            super( message( "mixins.annotation.declared.on.mixin.type.fix.remove.mixins.annotation" ) );
+            this.mixinsAnnotation = mixinsAnnotation;
+        }
+
+        public final void applyFix( @NotNull Project project, @NotNull ProblemDescriptor descriptor )
+        {
+            mixinsAnnotation.delete();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/sideEffects/common/Qi4jSideEffectConstants.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/sideEffects/common/Qi4jSideEffectConstants.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/sideEffects/common/Qi4jSideEffectConstants.java
new file mode 100644
index 0000000..d417575
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/sideEffects/common/Qi4jSideEffectConstants.java
@@ -0,0 +1,33 @@
+/*  Copyright 2008 Edward Yakop.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied.
+*
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.zest.ide.plugin.idea.sideEffects.common;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class Qi4jSideEffectConstants
+{
+    public static final String QUALIFIED_NAME_SIDE_EFFECTS = "org.qi4j.api.sideeffect.SideEffects";
+
+    public static final String QUALIFIED_NAME_SIDE_EFFECT_OF = "org.qi4j.api.sideeffect.SideEffectOf";
+    public static final String QUALIFIED_NAME_GENERIC_SIDE_EFFECT = "org.qi4j.api.sideeffect.GenericSideEffect";
+
+    private Qi4jSideEffectConstants()
+    {
+    }
+}
\ No newline at end of file


Mime
View raw message