001    /**
002     Licensed to the Apache Software Foundation (ASF) under one or more
003     contributor license agreements.  See the NOTICE file distributed with
004     this work for additional information regarding copyright ownership.
005     The ASF licenses this file to You under the Apache License, Version 2.0
006     (the "License"); you may not use this file except in compliance with
007     the License.  You may obtain a copy of the License at
008    
009          http://www.apache.org/licenses/LICENSE-2.0
010    
011     Unless required by applicable law or agreed to in writing, software
012     distributed under the License is distributed on an "AS IS" BASIS,
013     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     See the License for the specific language governing permissions and
015     limitations under the License.
016    */
017    package org.apache.commons.inject.api;
018    
019    import java.lang.annotation.Annotation;
020    import java.lang.reflect.Field;
021    import java.util.ArrayList;
022    import java.util.List;
023    
024    import org.apache.commons.inject.api.bind.IBinder;
025    import org.apache.commons.inject.api.bind.IModule;
026    import org.apache.commons.inject.api.bind.IBinder.IInjectionParticipator;
027    import org.apache.commons.inject.util.Exceptions;
028    
029    /**
030     * Abstract implementation of a module, which injects loggers into fields.
031     * The field must be annotated like this:
032     * <pre>
033     *   @InjLogger private Logger log;
034     * </pre>
035     * or
036     * <pre>
037     *   @InjLogger(id="LoggerId") private Logger log;
038     * </pre>
039     * The second example would create a logger with the id "LoggerId". The first
040     * example would use the class name as a default value. (The class being that
041     * class, which declares the field.
042     */
043    public abstract class AbstractLoggerInjectingModule<Log> implements IModule {
044    
045            @Override
046            public void configure(IBinder pBinder) {
047                    pBinder.add(new IInjectionParticipator() {
048                            @Override
049                            public List<IPoint<Object>> getPoints(IKey<?> pKey, Class<?> pType) {
050                                    final List<IPoint<Object>> points = new ArrayList<IPoint<Object>>();
051                                    final Field[] fields = pType.getDeclaredFields();
052                                    final Class<? extends Annotation> annotationClass = getAnnotationClass();
053                                    for (final Field f : fields) {
054                                            if (f.isAnnotationPresent(annotationClass)) {
055                                                    final Annotation annotation = f.getAnnotation(annotationClass);
056                                                    String id = getId(annotation, f.getDeclaringClass());
057                                                    if (id == null  ||  id.length() == 0) {
058                                                            id = f.getDeclaringClass().getName();
059                                                    }
060                                                    final Log logger = newLogger(id);
061                                                    points.add(new IPoint<Object>(){
062                                                            @Override
063                                                            public void injectTo(Object pInstance,
064                                                                            IInjector pInjector) {
065                                                                    try {
066                                                                            if (!f.isAccessible()) {
067                                                                                    f.setAccessible(true);
068                                                                            }
069                                                                            f.set(pInstance, logger);
070                                                                    } catch (Throwable t) {
071                                                                            throw Exceptions.show(t);
072                                                                    }
073                                                            }
074                                                    });
075                                            }
076                                    }
077                                    return points;
078                            }
079                    });
080            }
081    
082            /**
083             * Creates a new logger with the given Id. Subclasses <em>must</em>
084             * overwrite this to return a suitable logger implementation.
085             */
086            protected abstract Log newLogger(String pId);
087    
088            /**
089             * Returns the annotation class, which denotes suitable target fields.
090             * By default, the class {@link InjLogger} is used.
091             */
092            protected Class<? extends Annotation> getAnnotationClass() {
093                    return InjLogger.class;
094            }
095    
096            /**
097             * Called to calculate the Id, which is used to invoke {@link #newLogger(String)}.
098             * By default, {@link InjLogger#name()} is returned.
099             */
100            protected String getId(Annotation pAnnotation, Class<?> pClass) {
101                    final InjLogger injLogger = (InjLogger) pAnnotation;
102                    final String id = injLogger.id();
103                    if (id == null  ||  id.length() == 0) {
104                            return pClass.getName();
105                    } else {
106                            return id;
107                    }
108            }
109    }