001    /*
002     * Copyright © 2008, 2009 Pedro Agulló Soliveres.
003     * 
004     * This file is part of DirectJNgine.
005     *
006     * DirectJNgine is free software: you can redistribute it and/or modify
007     * it under the terms of the GNU General Public License as published by
008     * the Free Software Foundation, either version 3 of the License.
009     *
010     * DirectJNgine is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     * GNU General Public License for more details.
014     *
015     * You should have received a copy of the GNU General Public License
016     * along with DirectJNgine.  If not, see <http://www.gnu.org/licenses/>.
017     * 
018     * This software uses the ExtJs library (http://extjs.com), which is 
019     * distributed under the GPL v3 license (see http://extjs.com/license).
020     */
021    
022    package com.softwarementors.extjs.djn.api;
023    
024    import java.lang.reflect.Method;
025    import java.util.List;
026    
027    import com.softwarementors.extjs.djn.config.GlobalConfiguration;
028    import com.softwarementors.extjs.djn.config.RegisteredAction;
029    import com.softwarementors.extjs.djn.config.RegisteredApi;
030    import com.softwarementors.extjs.djn.config.RegisteredMethod;
031    import com.softwarementors.extjs.djn.config.RegisteredPollMethod;
032    import com.softwarementors.extjs.djn.router.PollRequestProcessor;
033    
034    public class ApiCodeGenerator {
035      
036      private static final String REMOTING_TYPE = "remoting";
037      private RegisteredApi api;
038      private GlobalConfiguration globalConfiguration;
039      
040      public ApiCodeGenerator( GlobalConfiguration globalConfiguration, RegisteredApi api ) {
041        assert globalConfiguration != null;
042        assert api != null;
043        
044        this.globalConfiguration = globalConfiguration;
045        this.api = api;
046      }
047    
048      private static final String TABS_1 = "  ";
049      private static final String TABS_2 = "    ";
050      private static final String TABS_3 = "      ";
051      
052      public void appendCode( StringBuilder result, boolean minify) {
053        assert result != null;
054        
055        appendNamespaceAndProviderUrlSection(result);
056        appendPollingUrlsSection(result, minify);
057        appendActionsSection(result, minify);
058      }
059    
060      private void appendNamespaceAndProviderUrlSection(StringBuilder result) {
061        assert result != null;
062        
063        result.append( "Ext.namespace( '"); result.append( this.api.getNamespace()); result.append("');\n" );
064        result.append('\n');
065        result.append( this.api.getNamespace() ); result.append( ".PROVIDER_BASE_URL=" ); appendJsExpressionToGetBaseUrl(result); result.append( '\''); result.append( this.globalConfiguration.getProvidersUrl() );  result.append( "';");
066        result.append('\n');
067        result.append('\n');
068      }
069    
070      private void appendJsExpressionToGetBaseUrl(StringBuilder result) {
071        assert result != null;
072        
073        result.append( "window.location.protocol + '//' + window.location.host + '/' + (window.location.pathname.split('/')[1]) + '/' + " );
074      }
075    
076      private void appendPollingUrlsSection(StringBuilder result, boolean minify) {
077        assert result != null;
078      
079        result.append( this.api.getNamespace() ); result.append( ".POLLING_URLS = {\n");
080        List<RegisteredPollMethod> pollMethods = this.api.getPollMethods();
081        for( int i = 0; i < pollMethods.size(); i++  ) {
082          RegisteredPollMethod pollMethod = pollMethods.get(i);
083          boolean isLast = i == pollMethods.size() - 1;
084          appendPollUrl(result, pollMethod, minify);
085          if( !isLast ) {
086           result.append( ", ");
087          }
088          result.append( "\n");
089        }
090        result.append( "}\n");
091        result.append( "\n");
092      }
093    
094      private void appendPollUrl(StringBuilder result, RegisteredPollMethod pollMethod, boolean minify) {
095        assert result != null;
096        assert pollMethod != null;
097        
098        result.append( TABS_1 ); result.append( pollMethod.getName()); result.append( " : ");
099        result.append( this.api.getNamespace() ); result.append( ".PROVIDER_BASE_URL + " );  result.append( "'" ); result.append( PollRequestProcessor.PATHINFO_POLL_PREFIX); result.append( pollMethod.getName() ); result.append( "' " );
100        if( !minify ) {
101          appendPollUrlExtraInformation(result, pollMethod);
102        }
103      }
104    
105      private void appendPollUrlExtraInformation(StringBuilder result, RegisteredPollMethod pollMethod) {
106        result.append( "/* "); appendMethodExtraInformation(pollMethod.getMethod(), pollMethod.getOwningClass(), false, result);
107        result.append( " -- calls "); result.append( pollMethod.getOwningClass().getName() ); result.append( "."); result.append( pollMethod.getMethod().getName() );
108        result.append( " */");
109      }
110    
111      private void appendActionsSection(StringBuilder result, boolean minify) {
112        assert result != null;
113        
114        appendActionsStart(result);    
115        List<RegisteredAction> actions = this.api.getActions();
116        
117        for( int i = 0; i < actions.size(); i++ ) {
118          boolean isLast = i == actions.size() - 1;
119          appendAction( actions.get(i), result, isLast, minify );
120        }
121        appendActionsEnd(result);
122      }
123    
124      private void appendActionsStart( StringBuilder result ) {
125        assert result != null;
126        
127        result.append( this.api.getNamespace() ); result.append( ".REMOTING_API"); result.append( " = {\n" );
128        
129        result.append("  url: " ); result.append( this.api.getNamespace() ); result.append( ".PROVIDER_BASE_URL") ; result.append( ",\n" );
130        result.append("  type: '" ); result.append( REMOTING_TYPE ); result.append( "',\n" );
131        result.append("  actions: {\n" );
132      }
133    
134      private void appendActionsEnd( StringBuilder result ) {
135        assert result != null;
136        
137        result.append( "  }\n" );
138        result.append( "}\n" );
139        result.append( '\n');
140      }
141      
142      private void appendAction(RegisteredAction action, StringBuilder result, boolean isLast, boolean minify ) {
143        assert action != null;
144        assert result != null;
145      
146        result.append( TABS_2 ); result.append( action.getName() ); result.append( ": [\n");
147        
148        List<RegisteredMethod> methods = action.getMethods();
149        for( int i = 0; i < methods.size(); i++ ) {
150          boolean isLastMethod = i == methods.size() - 1;
151          appendMethod( methods.get(i), result, isLastMethod, minify );
152        }
153        
154        result.append( TABS_2 ); result.append( "]" ); if( !isLast ) { result.append(","); } result.append('\n');
155      }
156    
157      private void appendMethod(RegisteredMethod method, StringBuilder result, boolean isLast, boolean minify) {
158        assert method != null;
159        assert result != null;
160    
161        result.append( TABS_3 ); result.append( "{\n");
162        result.append( TABS_3 ); result.append( "  name: '"); result.append( method.getName() ); result.append( "'" );
163        if( !minify ) {
164          appendMethodExtraInformation(method, result); 
165        }
166        result.append( ",\n");
167        result.append( TABS_3 ); result.append( "  len: "); result.append( method.getClientParameterCount() ); result.append( ",\n");
168        result.append( TABS_3 ); result.append( "  formHandler: "); result.append( method.getFormHandler() ); result.append( "\n");
169        result.append( TABS_3 ); result.append( "}" ); if( !isLast ) { result.append(","); } result.append( '\n');
170      }
171    
172      private void appendMethodExtraInformation(RegisteredMethod method, StringBuilder result) {
173        assert method != null;
174        assert result != null;
175        
176        result.append( "/*");
177    
178        appendMethodExtraInformation( method.getMethod(), method.getActionClass(), !method.getFormHandler(), result );
179    
180        if( method.getFormHandler()) {
181          result.append( " -- FORM HANDLER");
182        }
183        result.append( " */");
184      }
185      
186      private void appendMethodExtraInformation( Method method, Class<?> classOwningMethod, boolean writeJavaParameterTypes, StringBuilder result ) {
187        assert method != null;
188        assert classOwningMethod != null;
189        assert result != null;
190        
191        // Append parameters
192        result.append( "(");
193        if( writeJavaParameterTypes ) {
194          Class<?>[] parameterTypes = method.getParameterTypes();
195          for( int i=0; i < parameterTypes.length; i++ ) {
196            boolean isLast = i == parameterTypes.length - 1;
197            result.append( parameterTypes[i].getName() );
198            if( !isLast ) {
199              result.append( ", ");
200            }
201          }
202        }
203        result.append( ")");
204        
205        // Append result type
206        Class<?> resultType = method.getReturnType();
207        if( !resultType.equals(Void.class)) {
208          result.append( " => ");
209          result.append( resultType.getName());
210        }
211        
212      }
213    }