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