All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.seam.xml.bootstrap.XmlExtension Maven / Gradle / Ivy

/*
 * JBoss, Home of Professional Open Source
 * Copyright 2010, Red Hat, Inc., and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.jboss.seam.xml.bootstrap;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javax.enterprise.event.Observes;
import javax.enterprise.inject.Default;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.Annotated;
import javax.enterprise.inject.spi.AnnotatedConstructor;
import javax.enterprise.inject.spi.AnnotatedField;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedParameter;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.BeforeBeanDiscovery;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ProcessAnnotatedType;
import javax.enterprise.inject.spi.ProcessInjectionTarget;
import javax.enterprise.util.AnnotationLiteral;
import javax.inject.Named;

import org.jboss.seam.xml.annotations.internal.ApplyQualifiers;
import org.jboss.seam.xml.core.BeanResult;
import org.jboss.seam.xml.core.BeanResultType;
import org.jboss.seam.xml.core.GenericBeanResult;
import org.jboss.seam.xml.core.XmlConfiguredBean;
import org.jboss.seam.xml.core.XmlId;
import org.jboss.seam.xml.core.XmlResult;
import org.jboss.seam.xml.fieldset.FieldValueObject;
import org.jboss.seam.xml.fieldset.InjectionTargetWrapper;
import org.jboss.seam.xml.model.ModelBuilder;
import org.jboss.seam.xml.parser.ParserMain;
import org.jboss.seam.xml.parser.SaxNode;
import org.jboss.seam.xml.util.FileDataReader;
import org.jboss.weld.extensions.annotated.AnnotatedTypeBuilder;
import org.jboss.weld.extensions.util.AnnotationInstanceProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class XmlExtension implements Extension
{

   AnnotationInstanceProvider ac = new AnnotationInstanceProvider();

   static final String PROVIDERS_FILE = "META-INF/services/org.jboss.seam.xml.XmlExtension";

   List results = new ArrayList();

   Set> veto = new HashSet>();

   int count = 0;

   private static final Logger log = LoggerFactory.getLogger(XmlExtension.class);

   /**
    * map of syntetic bean id to a list of field value objects
    */
   Map> fieldValues = new HashMap>();

   List errors = new ArrayList();

   Map genericBeans = new HashMap();

   /**
    * This is the entry point for the extension
    */
   public void beforeBeanDiscovery(@Observes BeforeBeanDiscovery event, BeanManager beanManager)
   {
      log.info("Seam XML Config Starting...");
      List> providers = getDocumentProviders();
      for (Class cl : providers)
      {
         try
         {
            XmlDocumentProvider provider = cl.newInstance();
            provider.open();
            XmlDocument d;
            while ((d = provider.getNextDocument()) != null)
            {
               log.info("Reading XML file: " + d.getFileUrl());
               ParserMain parser = new ParserMain();
               ModelBuilder builder = new ModelBuilder();
               SaxNode parentNode = parser.parse(d.getInputSource(), d.getFileUrl(), errors);
               results.add(builder.build(parentNode));
            }
         }
         catch (Exception e)
         {
            errors.add(e);
         }
      }
      // build the generic bean data
      for (XmlResult r : results)
      {
         for (GenericBeanResult b : r.getGenericBeans())
         {
            genericBeans.put(b.getGenericBean(), b);
         }

         // add the qualifiers as we need them before we process the generic
         // bean info
         for (Class b : r.getQualifiers())
         {
            log.info("Adding XML Defined Qualifier: " + b.getName());
            event.addQualifier(b);
         }
      }

      for (XmlResult r : results)
      {
         if (!r.getProblems().isEmpty())
         {
            for (String i : r.getProblems())
            {
               errors.add(new RuntimeException(i));
            }
         }
         for (BeanResult b : r.getFieldValues().keySet())
         {
            int val = count++;
            fieldValues.put(val, r.getFieldValues().get(b));
            Map am = new HashMap();
            am.put("value", val);
            Annotation a = ac.get(XmlId.class, am);
            b.getBuilder().addToClass(a);
         }

         for (Class b : r.getInterceptorBindings())
         {
            log.info("Adding XML Defined Interceptor Binding: " + b.getName());
            event.addInterceptorBinding(b);
         }
         for (Entry, Annotation[]> b : r.getStereotypes().entrySet())
         {
            log.info("Adding XML Defined Stereotype: " + b.getKey().getName());
            event.addStereotype(b.getKey(), b.getValue());
         }
         for (BeanResult bb : r.getBeans())
         {
            GenericBeanResult found = null;
            for (Class g : genericBeans.keySet())
            {
               if (g.isAssignableFrom(bb.getType()))
               {
                  found = genericBeans.get(g);
                  break;
               }
            }
            if (found != null)
            {
               List> types = processGenericBeans(bb, found, beanManager);
               for (AnnotatedType i : types)
               {
                  event.addAnnotatedType(i);
               }
            }

            bb.getBuilder().addToClass(new AnnotationLiteral()
            {
            });
            AnnotatedType tp = bb.getBuilder().create();
            log.info("Adding XML definied bean: " + tp.getJavaClass().getName());
            event.addAnnotatedType(tp);

         }

         veto.addAll(r.getVeto());

      }
   }

   public  void processAnotated(@Observes ProcessAnnotatedType event, BeanManager manager)
   {
      if (event.getAnnotatedType().isAnnotationPresent(XmlConfiguredBean.class))
      {
         return;
      }
      // veto implementation
      if (veto.contains(event.getAnnotatedType().getJavaClass()))
      {
         log.info("Preventing installation of default bean: " + event.getAnnotatedType().getJavaClass().getName());
         event.veto();
         return;
      }
      boolean found = false;
      AnnotatedTypeBuilder builder = AnnotatedTypeBuilder.newInstance(event.getAnnotatedType());
      for (XmlResult r : results)
      {
         for (BeanResult i : r.getInterfaces())
         {
            if (i.getType().isAssignableFrom(event.getAnnotatedType().getJavaClass()))
            {
               found = true;
               builder.mergeAnnotations(i.getBuilder().create(), true);
            }
         }
      }
      if (found)
      {
         event.setAnnotatedType(builder.create());
      }

   }

   public  void processInjectionTarget(@Observes ProcessInjectionTarget event)
   {

      AnnotatedType at = event.getAnnotatedType();
      XmlId xid = at.getAnnotation(XmlId.class);
      if (xid != null)
      {
         log.info("Wrapping InjectionTarget to set field values: " + event.getAnnotatedType().getJavaClass().getName());
         List fvs = fieldValues.get(xid.value());
         event.setInjectionTarget(new InjectionTargetWrapper(event.getInjectionTarget(), fvs));
      }
      for (XmlResult r : results)
      {
         for (Entry, List> e : r.getInterfaceFieldValues().entrySet())
         {
            if (e.getKey().isAssignableFrom(event.getAnnotatedType().getJavaClass()))
            {
               log.info("Wrapping InjectionTarget to set field values based on interface " + e.getKey().getName() + ": " + event.getAnnotatedType().getJavaClass().getName());
               List fvs = e.getValue();
               event.setInjectionTarget(new InjectionTargetWrapper(event.getInjectionTarget(), fvs));
            }
         }
      }
   }

   public void processAfterBeanDeployment(@Observes AfterBeanDiscovery event)
   {
      for (Exception t : errors)
      {
         event.addDefinitionError(t);
      }
   }

   public List> getDocumentProviders()
   {
      List> ret = new ArrayList>();
      try
      {
         Enumeration urls = getClass().getClassLoader().getResources(PROVIDERS_FILE);
         while (urls.hasMoreElements())
         {

            URL u = urls.nextElement();
            String data = FileDataReader.readUrl(u);
            String[] providers = data.split("\\s");
            for (String provider : providers)
            {
               log.info("Loading XmlDocumentProvider: " + provider);
               Class res = null;
               try
               {
                  res = getClass().getClassLoader().loadClass(provider);
               }
               catch (ClassNotFoundException e)
               {
                  res = Thread.currentThread().getContextClassLoader().loadClass(provider);
               }
               if (res == null)
               {
                  throw new RuntimeException("Could not load XML configuration provider " + provider + " configured in file " + u.toString());
               }
               ret.add(res);
            }
         }
      }
      catch (Exception e)
      {
         throw new RuntimeException(e);
      }
      return ret;
   }

   /**
    * installs a set of secondary beans for a given generic bean, the secondary
    * beans have the same qualifiers added to them as the generic bean, in
    * addition the generic beans qualifiers are added whereever the
    * ApplyQualiers annotation is found
    * 
    */
   public List> processGenericBeans(BeanResult bean, GenericBeanResult genericBeans, BeanManager beanManager)
   {
      List> ret = new ArrayList>();
      AnnotatedType rootType = bean.getBuilder().create();
      // ret.add(rootType);
      Set qualifiers = new HashSet();

      for (Annotation i : rootType.getAnnotations())
      {
         if (beanManager.isQualifier(i.annotationType()))
         {
            qualifiers.add(i);
         }
      }
      for (BeanResult c : genericBeans.getSecondaryBeans())
      {

         AnnotatedType type = c.getBuilder().create();
         AnnotatedTypeBuilder gb = AnnotatedTypeBuilder.newInstance(type);
         if (c.getBeanType() == BeanResultType.SPECIALISE)
         {
            gb.readAnnotationsFromUnderlyingType();
         }
         // if the original type was qualified @Default we add that as well
         if (!isQualifierPresent(type, beanManager))
         {
            gb.addToClass(new DefaultLiteral());
         }
         // we always apply qualifiers to the actual type
         for (Annotation q : qualifiers)
         {
            gb.addToClass(q);
         }
         for (AnnotatedField f : type.getFields())
         {
            if (f.isAnnotationPresent(ApplyQualifiers.class))
            {
               // we need to manually add @default as it stops being applied
               // when
               // we add our qualifiers, however if we are deling with the main
               // type we do not
               // bother, as it should not be qualified @Default
               if (!isQualifierPresent(f, beanManager) && f.getJavaMember().getType() != rootType.getJavaClass())
               {
                  gb.addToField(f.getJavaMember(), new DefaultLiteral());
               }
               for (Annotation q : qualifiers)
               {
                  gb.addToField(f.getJavaMember(), q);
               }
            }
         }
         for (AnnotatedMethod m : type.getMethods())
         {

            if (m.isAnnotationPresent(ApplyQualifiers.class))
            {
               if (!isQualifierPresent(m, beanManager))
               {
                  gb.addToMethod(m.getJavaMember(), new DefaultLiteral());
               }
               for (Annotation q : qualifiers)
               {
                  gb.addToMethod(m.getJavaMember(), q);
               }
            }

            for (AnnotatedParameter p : m.getParameters())
            {

               if (p.isAnnotationPresent(ApplyQualifiers.class))
               {
                  if (!isQualifierPresent(p, beanManager) && p.getBaseType() != rootType.getJavaClass())
                  {
                     gb.addToMethodParameter(m.getJavaMember(), p.getPosition(), new DefaultLiteral());
                  }
                  for (Annotation q : qualifiers)
                  {
                     gb.addToMethodParameter(m.getJavaMember(), p.getPosition(), q);
                  }
               }
            }
         }

         for (AnnotatedConstructor con : type.getConstructors())
         {
            if (con.isAnnotationPresent(ApplyQualifiers.class))
            {
               if (!isQualifierPresent(con, beanManager))
               {
                  gb.addToConstructor((Constructor) con.getJavaMember(), new DefaultLiteral());
               }
               for (Annotation q : qualifiers)
               {
                  gb.addToConstructor((Constructor) con.getJavaMember(), q);
               }
            }

            for (AnnotatedParameter p : con.getParameters())
            {
               if (p.isAnnotationPresent(ApplyQualifiers.class) && p.getBaseType() != rootType.getJavaClass())
               {
                  if (!isQualifierPresent(p, beanManager))
                  {
                     gb.addToConstructorParameter((Constructor) con.getJavaMember(), p.getPosition(), new DefaultLiteral());
                  }
                  for (Annotation q : qualifiers)
                  {
                     gb.addToConstructorParameter((Constructor) con.getJavaMember(), p.getPosition(), q);
                  }
               }
            }
         }

         ret.add(gb.create());
      }
      return ret;
   }

   public boolean isQualifierPresent(Annotated f, BeanManager beanManager)
   {
      for (Annotation a : f.getAnnotations())
      {
         if (a.annotationType().equals(Named.class))
         {
            continue;
         }
         if (beanManager.isQualifier(a.annotationType()))
         {
            return true;
         }
      }
      return false;
   }

   public static class DefaultLiteral extends AnnotationLiteral implements Default
   {
   };
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy