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.io.PrintWriter;
022    import java.util.HashSet;
023    
024    import com.google.gwt.core.ext.GeneratorContext;
025    import com.google.gwt.core.ext.TreeLogger;
026    import com.google.gwt.core.ext.UnableToCompleteException;
027    import com.google.gwt.core.ext.typeinfo.JClassType;
028    import com.google.gwt.core.ext.typeinfo.JParameterizedType;
029    import com.google.gwt.user.rebind.AbstractSourceCreator;
030    import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
031    import com.google.gwt.user.rebind.SourceWriter;
032    
033    /**
034     * provides additional helper methods for generating source..
035     *
036     * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
037     */
038    public abstract class BaseSourceCreator extends AbstractSourceCreator {
039    
040        public static final TreeLogger.Type ERROR = TreeLogger.ERROR;
041        public static final TreeLogger.Type WARN = TreeLogger.WARN;
042        public static final TreeLogger.Type INFO = TreeLogger.INFO;
043        public static final TreeLogger.Type TRACE = TreeLogger.TRACE;
044        public static final TreeLogger.Type DEBUG = TreeLogger.DEBUG;
045        public static final TreeLogger.Type SPAM = TreeLogger.SPAM;
046        public static final TreeLogger.Type ALL = TreeLogger.ALL;
047    
048        protected final GeneratorContext context;
049        protected final JClassType source;
050        protected final String packageName;
051        protected final String shortName;
052        protected final String name;
053        protected TreeLogger logger;
054        protected SourceWriter sourceWriter;
055        private PrintWriter writer;
056    
057        static final private ThreadLocal<HashSet<String>> GENERATED_CLASSES = new ThreadLocal<HashSet<String>>();
058    
059        static public HashSet<String> getGeneratedClasses() {
060            HashSet<String> rc = GENERATED_CLASSES.get();
061            if (rc == null) {
062                rc = new HashSet<String>();
063                GENERATED_CLASSES.set(rc);
064            }
065            return rc;
066        }
067    
068        static public void clearGeneratedClasses() {
069            GENERATED_CLASSES.set(null);
070        }
071    
072        public BaseSourceCreator(TreeLogger logger, GeneratorContext context, JClassType source, String suffix) {
073            this.logger = logger;
074            this.context = context;
075            this.source = source;
076            this.packageName = source.getPackage().getName();
077    
078            if(source instanceof JParameterizedType)
079            {
080                    JParameterizedType ptype = (JParameterizedType)source;
081                            StringBuilder builder = new StringBuilder();
082                            for(JClassType type : ptype.getTypeArgs())
083                            {
084                                    builder.append("__");
085                                    builder.append(type.getParameterizedQualifiedSourceName().replace('.', '_'));
086                            }
087                            this.shortName = source.getSimpleSourceName() + builder.toString() + suffix;
088            }
089            else
090            {
091                    this.shortName = source.getSimpleSourceName() + suffix;
092            }
093    
094            this.name = packageName + "." + shortName;
095        }
096    
097        protected PrintWriter writer() throws UnableToCompleteException {
098            HashSet<String> classes = getGeneratedClasses();
099            if (classes.contains(name)) {
100                return null;
101            }
102            classes.add(name);
103            PrintWriter writer = context.tryCreate(logger, packageName, shortName);
104            if (writer == null) {
105                return null;
106            }
107            return writer;
108        }
109    
110        public interface Branch<R> {
111            R execute() throws UnableToCompleteException;
112        }
113    
114        protected <R> R branch(String msg, Branch<R> callable) throws UnableToCompleteException {
115            return branch(DEBUG, msg, callable);
116        }
117    
118        protected <R> R branch(TreeLogger.Type level, String msg, Branch<R> callable) throws UnableToCompleteException {
119            TreeLogger original = logger;
120            try {
121                logger = logger.branch(level, msg);
122                return callable.execute();
123            } finally {
124                logger = original;
125            }
126        }
127    
128        protected void error(String msg) throws UnableToCompleteException {
129            logger.log(ERROR, msg);
130            throw new UnableToCompleteException();
131        }
132    
133        protected void warn(String msg) throws UnableToCompleteException {
134            logger.log(WARN, msg);
135            throw new UnableToCompleteException();
136        }
137    
138        protected void info(String msg) throws UnableToCompleteException {
139            logger.log(INFO, msg);
140        }
141    
142        protected void debug(String msg) throws UnableToCompleteException {
143            logger.log(DEBUG, msg);
144        }
145    
146        protected void trace(String msg) throws UnableToCompleteException {
147            logger.log(TRACE, msg);
148        }
149    
150        protected JClassType find(Class<?> type) throws UnableToCompleteException {
151            return find(type.getName().replace('$', '.'));
152        }
153    
154        protected JClassType find(String type) throws UnableToCompleteException {
155            return RestServiceGenerator.find(logger, context, type);
156        }
157    
158        protected BaseSourceCreator i(int i) {
159            if (i == 1) {
160                this.sourceWriter.indent();
161            } else if (i == -1) {
162                this.sourceWriter.outdent();
163            } else {
164                throw new IllegalArgumentException();
165            }
166            return this;
167        }
168    
169        protected BaseSourceCreator p(String value) {
170            this.sourceWriter.println(value);
171    
172            // System.out.println(value);
173            return this;
174        }
175    
176        protected BaseSourceCreator p() {
177            this.sourceWriter.println();
178            return this;
179        }
180    
181        static String join(int []values, String sep) {
182            StringBuilder sb = new StringBuilder();
183            for(int i =0; i < values.length; i++) {
184                if( i!=0 ) {
185                    sb.append(sep);
186                }
187                sb.append(values[i]);
188            }
189            return sb.toString();
190        }
191    
192        static String join(Object []values, String sep) {
193            StringBuilder sb = new StringBuilder();
194            for(int i =0; i < values.length; i++) {
195                if( i!=0 ) {
196                    sb.append(sep);
197                }
198                sb.append(values[i]);
199            }
200            return sb.toString();
201        }
202    
203        final public String create() throws UnableToCompleteException {
204            writer = writer();
205            if (writer == null) {
206                return name;
207            }
208            logger = logger.branch(TreeLogger.DEBUG, "Generating: " + name);
209    
210            ClassSourceFileComposerFactory composerFactory = createComposerFactory();
211            sourceWriter = composerFactory.createSourceWriter(context, writer);
212    
213            generate();
214            sourceWriter.commit(logger);
215            return name;
216        }
217    
218        abstract protected ClassSourceFileComposerFactory createComposerFactory() throws UnableToCompleteException;
219    
220        abstract protected void generate() throws UnableToCompleteException;
221    }