001    /**
002     * Copyright (C) 2009-2011 the original author or authors.
003     * See the notice.md file distributed with this work for additional
004     * information regarding copyright ownership.
005     *
006     * Licensed under the Apache License, Version 2.0 (the "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package org.fusesource.restygwt.rebind;
020    
021    import java.util.ArrayList;
022    import java.util.List;
023    import java.util.Map;
024    
025    import org.fusesource.restygwt.client.Method;
026    import org.fusesource.restygwt.client.ModelChange;
027    import org.fusesource.restygwt.client.cache.Domain;
028    
029    import com.google.gwt.core.ext.TreeLogger;
030    import com.google.gwt.core.ext.UnableToCompleteException;
031    import com.google.gwt.core.ext.typeinfo.JClassType;
032    import com.google.gwt.core.ext.typeinfo.JMethod;
033    
034    /**
035     * Implementation for an annotationparser which is responsible to put
036     * annotation-data from ModelChange annotations to {@link Method} instances.
037     *
038     * This class transports information about ModelChangeEvents to be triggered,
039     * when some servicemethods have been called.
040     *
041     * @author <a href="mailto:andi.balke@gmail.com">andi</<a>
042     */
043    public class ModelChangeAnnotationResolver implements AnnotationResolver {
044    
045        @Override
046        public Map<String, String[]> resolveAnnotation(TreeLogger logger, JClassType source, JMethod method,
047                final String restMethod) throws UnableToCompleteException {
048            ModelChange classAnnot = source.getAnnotation(ModelChange.class);
049            String[] serviceDomains = null;
050            ModelChange methodAnnot = method.getAnnotation(ModelChange.class);
051            final Map<String, String[]> ret = new java.util.HashMap<String, String[]>();
052    
053            if(null != source.getAnnotation(Domain.class)) {
054                serviceDomains = getAnnotationsAsStringArray(
055                    source.getAnnotation(Domain.class).value());
056    
057                // cachedomain annotations are resolved in any case
058                logger.log(TreeLogger.TRACE, "found ``Domain`` annotation with " + serviceDomains.length
059                        + " domains in " + source.getName());
060                ret.put(Domain.CACHE_DOMAIN_KEY, serviceDomains);
061            }
062    
063            if (methodAnnot != null) {
064                String[] domains = null;
065    
066                if (methodAnnot.domain() == null
067                        || methodAnnot.domain().length == 0) {
068                    if (serviceDomains == null) {
069                        logger.log(TreeLogger.ERROR, "found method annotation with empty domain definition in " +
070                                source.getName() + " on method " + method.getName());
071                        throw new UnableToCompleteException();
072                    }
073                    logger.log(TreeLogger.TRACE, "found ``Domain`` annotation with " + serviceDomains.length
074                            + " domains '" + serviceDomains + "' "
075                            + source.getName() + " on method " + method.getName());
076                    domains = serviceDomains;
077                } else {
078                    domains = getAnnotationsAsStringArray(methodAnnot.domain());
079                    logger.log(TreeLogger.TRACE, "use domain from ModelChange annotation at: "
080                            + source.getName() + "#" + method.getName() + ": " + domains);
081                }
082    
083                // method annotation match
084                ret.put(ModelChange.MODEL_CHANGED_DOMAIN_KEY, domains);
085                return ret;
086            }
087    
088            if (classAnnot != null
089                    && classAnnot.on() != null) {
090                for (String s : classAnnot.on()) {
091                    if (s.toUpperCase().equals(restMethod.toUpperCase())) {
092                        String[] domains = null;
093    
094                        if (classAnnot.domain() == null
095                                || classAnnot.domain().equals("")) {
096                            if (serviceDomains == null) {
097                                logger.log(TreeLogger.ERROR, "found class annotation with empty domain definition in " +
098                                        source.getName());
099                                throw new UnableToCompleteException();
100                            }
101                            domains = serviceDomains;
102                        } else {
103                            domains = getAnnotationsAsStringArray(classAnnot.domain());
104                        }
105    
106                        // class annotation match for current method
107                        ret.put(ModelChange.MODEL_CHANGED_DOMAIN_KEY, domains);
108                        return ret;
109                    }
110                }
111            }
112    
113            return ret;
114        }
115    
116        /**
117         * convert an array of classes to an array of strings to be usable in js context.
118         *
119         * @param classes
120         * @return
121         */
122        private String[] getAnnotationsAsStringArray(final Class[] classes) {
123            if (null == classes) return null;
124    
125            List<String> ret = new ArrayList<String>();
126    
127            for(Class c: classes) {
128                ret.add(c.getName());
129            }
130    
131            return ret.toArray(new String[ret.size()]);
132        }
133    }