diff --git a/build.xml b/build.xml index 39d67768494..b88687f74f1 100644 --- a/build.xml +++ b/build.xml @@ -104,7 +104,7 @@ Must specify the parameter for apiConfiguration - eg. -DapiConfiguration==../api-server-lib/java/config/apiConfiguration.json + eg. -DapiConfiguration=../api-server-lib/java/config/apiConfiguration.json apiConfiguration to be used : ${apiConfiguration} @@ -120,6 +120,26 @@ + + + + Must specify the parameter for apiConfiguration + eg. -DapiConfiguration=../api-server-lib/as3/config/apiConfiguration.json + + + apiConfiguration to be used : ${apiConfiguration} + + + + + + + + + + + + diff --git a/conf/as3/sample/as3_code_gen_conf.json b/conf/as3/sample/as3_code_gen_conf.json new file mode 100644 index 00000000000..7d95d614b7c --- /dev/null +++ b/conf/as3/sample/as3_code_gen_conf.json @@ -0,0 +1,30 @@ +{ + "apiUrl":"http://swagr.api.wordnik.com/v4/", + + "apiKey":"special-key", + + "defaultServiceBaseClass":"SwaggerApi", + + "defaultModelBaseClass":"Object", + + "serviceBaseClasses":{}, + + "defaultModelImports":[], + + "defaultServiceImports":["mx.rpc.AsyncToken","mx.utils.UIDUtil", + "flash.utils.Dictionary","flash.events.EventDispatcher", + "com.wordnik.swagger.common.ApiUserCredentials","com.wordnik.swagger.event.Response", + "com.wordnik.swagger.common.SwaggerApi"], + + "modelPackageName":"com.wordnik.swagger.model", + + "apiPackageName":"com.wordnik.swagger.api", + + "ignoreMethods":["WordAPI.getWordFrequency","WordAPI.getAudio","WordAPI.getWordStats","WordAPI.getFlickrImages"], + + "ignoreModels":["wordStats","photo","sizes"], + + "outputDirectory":"../api-server-temp/as3ApiSDK/src/main/as3/com/wordnik/swagger/", + + "libraryHome":"../api-server-temp/as3ApiSDK" +} \ No newline at end of file diff --git a/conf/as3/structure/lib/ASAXB-0.1.1.swc b/conf/as3/structure/lib/ASAXB-0.1.1.swc new file mode 100644 index 00000000000..c9359026784 Binary files /dev/null and b/conf/as3/structure/lib/ASAXB-0.1.1.swc differ diff --git a/conf/as3/structure/src/main/as3/com/wordnik/swagger/common/ApiInvoker.as b/conf/as3/structure/src/main/as3/com/wordnik/swagger/common/ApiInvoker.as new file mode 100644 index 00000000000..79c6e68a9c0 --- /dev/null +++ b/conf/as3/structure/src/main/as3/com/wordnik/swagger/common/ApiInvoker.as @@ -0,0 +1,223 @@ +package com.wordnik.swagger.common +{ + import asaxb.xml.bind.ASAXBContext; + import asaxb.xml.bind.Unmarshaller; + + import com.wordnik.swagger.event.ApiClientEvent; + import com.wordnik.swagger.event.Response; + import com.wordnik.swagger.common.ApiUserCredentials; + + import flash.events.EventDispatcher; + import flash.utils.Dictionary; + import flash.utils.describeType; + import flash.xml.XMLDocument; + import flash.xml.XMLNode; + + import mx.messaging.ChannelSet; + import mx.messaging.channels.HTTPChannel; + import mx.messaging.messages.HTTPRequestMessage; + import mx.rpc.AsyncToken; + import mx.rpc.events.FaultEvent; + import mx.rpc.events.ResultEvent; + import mx.rpc.http.HTTPService; + import mx.rpc.xml.SimpleXMLEncoder; + import mx.utils.ObjectUtil; + + + public class ApiInvoker extends EventDispatcher + { + + private var _apiUsageCredentials:ApiUserCredentials; + internal var _apiProxyServerUrl:String = "http://apihost.wordnik.com/"; + private var _baseUrl: String = "http://beta.wordnik.com/api/"; + internal var _useProxyServer: Boolean = true; + private var _proxyHostName:String = "api.wordnik.com"; + private var _apiPath: String = "/v4"; + + public var _apiEventNotifier:EventDispatcher; + + private static const DELETE_DATA_DUMMY:String = "dummyDataRequiredForDeleteOverride"; + private static const X_HTTP_OVERRIDE_KEY:String = "X-HTTP-Method-Override"; + private static const CONTENT_TYPE_HEADER_KEY:String = "Content-Type"; + + public function ApiInvoker(apiUsageCredentials: ApiUserCredentials, eventNotifier: EventDispatcher, useProxy: Boolean = true) { + _apiUsageCredentials = apiUsageCredentials; + _useProxyServer = useProxy; + if(_apiUsageCredentials.hostName != null){ + _proxyHostName = _apiUsageCredentials.hostName; + } + _apiPath = _apiUsageCredentials.apiPath; + _apiProxyServerUrl = _apiUsageCredentials.apiProxyServerUrl; + _apiEventNotifier = eventNotifier; + } + + public function invokeAPI(authToken: String , resourceURL: String, method: String, queryParams: Dictionary, postObject: Object): AsyncToken { + //make the communication + if(_useProxyServer) { + resourceURL = resourceURL = _apiProxyServerUrl + resourceURL; + } + else{ + resourceURL = resourceURL = "http://"+ _proxyHostName + _apiPath + resourceURL; + } + + var counter: int = 0; + var symbol: String = "&"; + var paramValue: Object; + for (var paramName:String in queryParams) { + paramValue = queryParams[paramName]; + //var key:String = paramName; + // do stuff + symbol = "&"; + if(counter == 0){ + symbol = "?"; + } + resourceURL = resourceURL + symbol + paramName + "=" + paramValue.toString(); + counter++; + + } + //create a httpservice and invoke the rest url waiting for response + var requestHeader:Object = new Object(); + resourceURL = ApiUrlHelper.appendTokenInfo(resourceURL, requestHeader, _apiUsageCredentials); + var bodyData:String = marshal( postObject);//restRequest.postData; + + return doRestCall(resourceURL, onApiRequestResult, onApiRequestFault, method, bodyData, requestHeader, "application/xml"); + + + } + + private function doRestCall( url : String, resultFunction : Function, faultFunction : Function = null, + restMethod : String = "GET", + bodyData : Object = null, headers: Object = null, contentType:String = "application/xml" ) : AsyncToken + { + var httpService : HTTPService = new HTTPService( ); + + if(headers == null){ + headers = new Object(); + } + httpService.method = restMethod; + + if ( restMethod.toUpperCase() != HTTPRequestMessage.GET_METHOD ) + { + //httpService.method = HTTPRequestMessage.POST_METHOD; - not required as we're using the proxy + if( bodyData == null ) + { + bodyData = new Object(); + } + + if(restMethod == HTTPRequestMessage.DELETE_METHOD){ + headers[X_HTTP_OVERRIDE_KEY]= HTTPRequestMessage.DELETE_METHOD; + bodyData = DELETE_DATA_DUMMY; + } + else{ + headers[CONTENT_TYPE_HEADER_KEY]= contentType; + } + } + else + { + //if the request type is GET and content type is xml then the Flex HTTPService converts it to a POST ... yeah + contentType = null; + } + + httpService.url = url; + httpService.contentType = contentType; + httpService.resultFormat = "e4x"; + httpService.headers = headers; + httpService.addEventListener( ResultEvent.RESULT, resultFunction ); + if( faultFunction != null ) + { + httpService.addEventListener( FaultEvent.FAULT, faultFunction ); + } + if(_useProxyServer){ + httpService.useProxy = true; + + var channelSet: ChannelSet = new ChannelSet(); + var httpChannel: HTTPChannel = new HTTPChannel(); + httpChannel.uri = ApiUrlHelper.getProxyUrl(_proxyHostName); + channelSet.addChannel(httpChannel); + httpService.channelSet = channelSet; + } + return httpService.send( bodyData ); + } + + private function onApiRequestResult(event:ResultEvent):void + { + var completionListener: Function = event.token.completionListener; + var result: Object = event.result; + var resultType: Class = event.token.returnType; + var resultObject:Object; + if(resultType != null) { + var context:ASAXBContext = ASAXBContext.newInstance(resultType); + var unmarshaller:Unmarshaller = context.createUnmarshaller(); + var resultXML: XML = new XML(event.result); + resultObject = unmarshaller.unmarshal(resultXML); + + } + var response : Response = new Response(true, resultObject); + response.requestId = event.token.requestId; + var successEventType: String = event.token.completionEventType != null ? event.token.completionEventType : ApiClientEvent.SUCCESS_EVENT; + + if (_apiEventNotifier != null) { //dispatch event via assigned dispatcher + var successEvent: ApiClientEvent = new ApiClientEvent(successEventType); + successEvent.response = response; + _apiEventNotifier.dispatchEvent(successEvent); + } + } + + private function onApiRequestFault(event:FaultEvent):void + { + var completionListener: Function = event.token.completionListener; + if(completionListener != null){ + completionListener.call( null, new Response( false, null, event.fault.faultString) ); + } + + var failureEventType: String = event.token.completionEventType != null ? event.token.completionEventType : ApiClientEvent.FAILURE_EVENT; + + if (_apiEventNotifier != null) { //dispatch event via assigned dispatcher + var failureEvent: ApiClientEvent = new ApiClientEvent(failureEventType); + failureEvent.response = new Response( false, null, event.fault.faultString); + _apiEventNotifier.dispatchEvent(failureEvent); + } + } + + + public function marshal(source:Object):XML + { + var writer:XMLWriter=new XMLWriter(); + var objDescriptor:XML=describeType(source); + var property:XML; + var propertyType:String; + var propertyValue:Object; + + var qualifiedClassName:String=objDescriptor.@name; + qualifiedClassName=qualifiedClassName.replace("::","."); + writer.xml.setName(qualifiedClassName); + + for each(property in objDescriptor.elements("variable")){ + propertyValue=source[property.@name]; + if (propertyValue!=null){ + if (ObjectUtil.isSimple(propertyValue)){ + writer.addProperty(property.@name, propertyValue.toString()); + } + else { + writer.addProperty(property.@name, marshal(propertyValue).toXMLString()); + } + } + } + for each(property in objDescriptor.elements("accessor")){ + if (property.@access=="readonly"){ + continue; + } + propertyValue=source[property.@name]; + if (source[property.@name]!=null){ + if (ObjectUtil.isSimple(propertyValue)){ + writer.addProperty(property.@name, propertyValue.toString()); + } + else { + writer.addProperty(property.@name, marshal(propertyValue).toXMLString()); + } + } + } + return writer.xml; + } + } +} \ No newline at end of file diff --git a/conf/as3/structure/src/main/as3/com/wordnik/swagger/common/ApiUrlHelper.as b/conf/as3/structure/src/main/as3/com/wordnik/swagger/common/ApiUrlHelper.as new file mode 100644 index 00000000000..844f0deb16d --- /dev/null +++ b/conf/as3/structure/src/main/as3/com/wordnik/swagger/common/ApiUrlHelper.as @@ -0,0 +1,42 @@ +package com.wordnik.swagger.common { +import com.wordnik.swagger.common.ApiUserCredentials; + +/** + * @private + * Internal class for the Rest client + */ +internal class ApiUrlHelper { + + private static const API_URL_KEY:String = "api_key"; + private static const AUTH_TOKEN_URL_KEY:String = "auth_token"; + + private static const HOST_PROXY_PATH:String = "/v4/messagebroker/restproxy"; + private static const HTTP_URL_PREFIX:String = "http://"; + + internal static function appendTokenInfo(restUrl:String, requestHeader: Object, credentials: ApiUserCredentials): String { + //wordnik credentials presence validated on client initialization and not here + if(restUrl.indexOf("?") == -1){ + restUrl += ( "?" + API_URL_KEY + "=" + credentials.apiToken ); + } + else{ + restUrl += ( "&" + API_URL_KEY + "=" + credentials.apiToken ); + } + requestHeader.api_key = credentials.apiToken; + + if(credentials.authToken != null && credentials.authToken != ""){ + restUrl += ( "&" + AUTH_TOKEN_URL_KEY + "=" + credentials.authToken ); + requestHeader.auth_token = credentials.authToken; + } + + return restUrl; + } + + internal static function getProxyUrl(hostName: String): String{ + if (hostName.charAt(hostName.length - 1) == "/") //remove trailing slash + { + hostName = hostName.substring(0, hostName.length - 1); + } + return HTTP_URL_PREFIX + hostName + HOST_PROXY_PATH; + } +} +} diff --git a/conf/as3/structure/src/main/as3/com/wordnik/swagger/common/ApiUserCredentials.as b/conf/as3/structure/src/main/as3/com/wordnik/swagger/common/ApiUserCredentials.as new file mode 100644 index 00000000000..412e3c31441 --- /dev/null +++ b/conf/as3/structure/src/main/as3/com/wordnik/swagger/common/ApiUserCredentials.as @@ -0,0 +1,55 @@ +package com.wordnik.swagger.common { + +/** + * Wordnik Api account credentials. The info is used to authenticate with the Wordnik API and perform + * account-specific user actions + */ +public class ApiUserCredentials { + /** + * All requests must be signed with your Wordnik API key + */ + public var apiToken:String; + /** + * A valid auth_token which is necessary for certain operations - currently, user accounts and list-related CRUD operations + */ + public var authToken:String; + /** + * The userId which is required for certain operations - currently, get user lists + */ + public var userId:Number; + /** + * The host name for the Wordnik Rest API eg. api.wordnik.com + */ + public var hostName:String; + + /** + * The base path to the api resources - used along with the hostname + * eg. /v4 + */ + public var apiPath: String; + + /** + * If a proxy server has been set up for the services specify the URL here. This value is used when the Api is invoked with + * the value useProxy as true + */ + public var apiProxyServerUrl: String; + + /** + * Constructor of ApiUserCredentials + * @param apiToken All requests must be signed with your Wordnik API key + * @param authToken A valid auth_token which is necessary for certain operations - currently, user accounts and list-related CRUD operations + * @param hostName The host name for the Wordnik Rest API eg. api.wordnik.com + * @param userId The userId which is required for certain operations - currently, get user lists + */ + public function ApiUserCredentials(apiToken: String, authToken: String = null, hostName: String = null, userId: Number = -1, + apiPath: String = "", apiProxyServerUrl: String="") { + this.hostName = hostName; + this.apiToken = apiToken; + this.authToken = authToken; + this.userId = userId; + this.apiPath = apiPath; + this.apiProxyServerUrl = apiProxyServerUrl; + } + +} +} \ No newline at end of file diff --git a/conf/as3/structure/src/main/as3/com/wordnik/swagger/common/SwaggerApi.as b/conf/as3/structure/src/main/as3/com/wordnik/swagger/common/SwaggerApi.as new file mode 100644 index 00000000000..7c512587d1a --- /dev/null +++ b/conf/as3/structure/src/main/as3/com/wordnik/swagger/common/SwaggerApi.as @@ -0,0 +1,82 @@ +package com.wordnik.swagger.common +{ + import com.wordnik.swagger.common.ApiUserCredentials; + + import flash.events.EventDispatcher; + import flash.events.IEventDispatcher; + + import mx.utils.UIDUtil; + + public class SwaggerApi extends EventDispatcher + { + + protected var _apiUsageCredentials:ApiUserCredentials; + protected var _apiEventNotifier:EventDispatcher; + protected var _apiInvoker: ApiInvoker; + + protected var apiProxyServerUrl:String = "http://apihost.wordnik.com/"; + protected var _baseUrl: String = "http://beta.wordnik.com/api/"; + protected var _useProxyServer: Boolean = true; + protected var proxyHostName:String = "api.wordnik.com"; + + protected static const DELETE_DATA_DUMMY:String = "dummyDataRequiredForDeleteOverride"; + protected static const X_HTTP_OVERRIDE_KEY:String = "X-HTTP-Method-Override"; + protected static const CONTENT_TYPE_HEADER_KEY:String = "Content-Type"; + + + /** + * Constructor for the api client + * @param apiCredentials Wrapper object for tokens and hostName required towards authentication + * @param eventDispatcher Optional event dispatcher that when provided is used by the SDK to dispatch any Response + */ + public function SwaggerApi(apiCredentials: ApiUserCredentials, eventDispatcher: EventDispatcher = null) { + super(); + _apiUsageCredentials = apiCredentials; + _apiEventNotifier = eventDispatcher; + } + + public function useProxyServer(value:Boolean, proxyServerUrl: String = null):void { + _useProxyServer = value; + } + + protected function getApiInvoker():ApiInvoker { + if(_apiInvoker == null){ + if(_apiEventNotifier == null){ + _apiEventNotifier = this; + } + _apiInvoker = new ApiInvoker(_apiUsageCredentials, _apiEventNotifier, _useProxyServer); + } + return _apiInvoker; + } + + protected function getUniqueId():String { + return UIDUtil.createUID(); + } + + /** + * Method for returning the path value + * For a string value an empty value is returned if the value is null + * @param value + * @return + */ + protected static function toPathValue(value: Object): String { + if(value is Array){ + return arrayToPathValue(value as Array); + } + return value == null ? "" : value.toString(); + } + + /** + * Method for returning a path value + * For a list of objects a comma separated string is returned + * @param objects + * @return + */ + protected static function arrayToPathValue(objects: Array): String { + var out: String = ""; + + return objects.join(","); + } + + } +} \ No newline at end of file diff --git a/conf/as3/structure/src/main/as3/com/wordnik/swagger/common/XMLWriter.as b/conf/as3/structure/src/main/as3/com/wordnik/swagger/common/XMLWriter.as new file mode 100644 index 00000000000..067f49e6301 --- /dev/null +++ b/conf/as3/structure/src/main/as3/com/wordnik/swagger/common/XMLWriter.as @@ -0,0 +1,28 @@ +package com.wordnik.swagger.common +{ + public class XMLWriter + { + public var xml:XML; + + public function XMLWriter() + { + xml=; + } + + public function reset():void { + xml=new XML(); + } + + public function addProperty(propertyName:String, propertyValue:String):XML { + var xmlProperty:XML= + xmlProperty.setName(propertyName); + xmlProperty.appendChild(propertyValue); + xml.appendChild(xmlProperty); + return xmlProperty; + } + + public function addAttribute(propertyName:String, attribute:String, attributeValue:String):void { + xml.elements(propertyName)[0].@[attribute]=attributeValue; + } + } +} \ No newline at end of file diff --git a/conf/as3/structure/src/main/as3/com/wordnik/swagger/event/ApiClientEvent.as b/conf/as3/structure/src/main/as3/com/wordnik/swagger/event/ApiClientEvent.as new file mode 100644 index 00000000000..5484669a3f2 --- /dev/null +++ b/conf/as3/structure/src/main/as3/com/wordnik/swagger/event/ApiClientEvent.as @@ -0,0 +1,36 @@ +package com.wordnik.swagger.event { +import com.wordnik.swagger.event.Response; + +import flash.events.Event; + +/** + * Event dispatched by the SDK to communicate success events and failure events. + * If a custom dispatcher has been assigned by the consumer on the WordnikClient then the dispatcher dispatches + * the ApiClientEvent to indicate success or failure of the invocation using the Response + */ +public class ApiClientEvent extends Event{ + + /** + * Event type to indicate a unsuccessful invocation + */ + public static const FAILURE_EVENT:String = "unsuccesfulInvocation"; + + /** + * Event type to indicate a successful invocation + */ + public static const SUCCESS_EVENT:String = "successfulInvocation"; + + /** + * The Response object which contains response info + */ + public var response: Response; + /** + * Any additional info + */ + public var message:String; + + public function ApiClientEvent(type:String,bubbles:Boolean = false,cancelable:Boolean = false) { + super(type, bubbles, cancelable); + } +} +} \ No newline at end of file diff --git a/conf/as3/structure/src/main/as3/com/wordnik/swagger/event/Response.as b/conf/as3/structure/src/main/as3/com/wordnik/swagger/event/Response.as new file mode 100644 index 00000000000..f09aae7e90a --- /dev/null +++ b/conf/as3/structure/src/main/as3/com/wordnik/swagger/event/Response.as @@ -0,0 +1,52 @@ +package com.wordnik.swagger.event { + +/** + * Response contains info on the result of a Wordnik API invocation. + * A completion listener will expect this WNResult object as a parameter. + */ +public class Response { + + /** + * Indicates whether the invoked operation failed or succeeded + */ + public var isSuccess:Boolean; + + /** + * The payload of the succesful operation eg. a Word in a WordRequest + */ + public var payload:Object; + + /** + * Error message in case of failure + */ + public var errorMessage:String; + + /** + * A request Id that was passed in by the user as a param when invoking the operation + */ + public var requestId:String; + private static const API_ERROR_MSG:String = "Api error response: "; + + public function Response(isSuccessful: Boolean, payload: Object = null, errorMessage: String = null, requestId: String = null) { + this.isSuccess = isSuccessful; + this.payload = payload; + this.errorMessage = getFriendlyMessage(errorMessage); + } + + private static function getFriendlyMessage(errorMessage: String): String{ + var result: String = errorMessage; + if(errorMessage == null) + return null; + var errorCode: String; + var errorCodeArray: Array = errorMessage.match(/(?<=HTTP\/1.1 )[0-9][0-9][0-9]/); + if(errorCodeArray != null && errorCodeArray.length == 1){ + errorCode = String(errorCodeArray[0]); + } + var msgArray: Array = errorMessage.match(/(?<=HTTP\/1.1 [0-9][0-9][0-9] )[^]*/); + if(msgArray != null && msgArray.length == 1){ + result = API_ERROR_MSG + String(msgArray[0]); + } + return result; + } +} +} \ No newline at end of file diff --git a/conf/as3/structure/src/main/as3/com/wordnik/swagger/exception/ApiError.as b/conf/as3/structure/src/main/as3/com/wordnik/swagger/exception/ApiError.as new file mode 100644 index 00000000000..13d09415829 --- /dev/null +++ b/conf/as3/structure/src/main/as3/com/wordnik/swagger/exception/ApiError.as @@ -0,0 +1,10 @@ +package com.wordnik.swagger.exception +{ + public class ApiError extends Error + { + public function ApiError(id:*=0, message:*="") + { + super(message,id); + } + } +} \ No newline at end of file diff --git a/conf/as3/structure/src/main/as3/com/wordnik/swagger/exception/ApiErrorCodes.as b/conf/as3/structure/src/main/as3/com/wordnik/swagger/exception/ApiErrorCodes.as new file mode 100644 index 00000000000..abe12178361 --- /dev/null +++ b/conf/as3/structure/src/main/as3/com/wordnik/swagger/exception/ApiErrorCodes.as @@ -0,0 +1,34 @@ +package com.wordnik.swagger.exception +{ + public class ApiErrorCodes + { + /** + * System exception. + */ + public static const SYSTEM_EXCEPTION: Number = 0; + + /** + * With Arguments as current key. + */ + public static const API_KEY_NOT_VALID: Number = 1000; + /** + * With arguments as current token value + */ + public static const AUTH_TOKEN_NOT_VALID: Number = 1001; + /** + * With arguments as input JSON and output class anme + */ + public static const ERROR_CONVERTING_JSON_TO_JAVA: Number = 1002; + /** + * With arguments as JAVA class name + */ + public static const ERROR_CONVERTING_JAVA_TO_JSON: Number = 1003; + + public static const ERROR_FROM_WEBSERVICE_CALL: Number = 1004; + /** + * With arguments as current API server name + */ + public static const API_SERVER_NOT_VALID: Number = 1005; + + } +} \ No newline at end of file diff --git a/conf/as3/structure/src/main/as3/com/wordnik/swagger/model/DefinitionWrapper.as b/conf/as3/structure/src/main/as3/com/wordnik/swagger/model/DefinitionWrapper.as new file mode 100644 index 00000000000..82e48aa1d64 --- /dev/null +++ b/conf/as3/structure/src/main/as3/com/wordnik/swagger/model/DefinitionWrapper.as @@ -0,0 +1,13 @@ +package com.wordnik.swagger.model +{ + public class DefinitionWrapper + { + /** + * + * + * + */ + [XmlElements(name="definition", type="com.wordnik.swagger.model.Definition")] + public var definition: Array = new Array(); + } +} \ No newline at end of file diff --git a/conf/as3/templates/EnumObject.st b/conf/as3/templates/EnumObject.st new file mode 100644 index 00000000000..9cbc2c661c5 --- /dev/null +++ b/conf/as3/templates/EnumObject.st @@ -0,0 +1,30 @@ +package $packageName$; + +$imports:{ import | +import $import$; +}$ + +/** + * $enum.description$ + * NOTE: This class is auto generated by the drive code generator program so please do not edit the class manually. + * @author deepak + * + */ +public enum $className$ { + + $values: { value | $value.name$($value.value$)};separator=", "$; + + final $enumValueType$ value; + + $className$($enumValueType$ value) { + this.value = value; + } + + public $enumValueType$ getValue() { + return value; + } + + @Override public String toString() { + return String.valueOf(this.getValue()); + } +}; \ No newline at end of file diff --git a/conf/as3/templates/ModelObject.st b/conf/as3/templates/ModelObject.st new file mode 100644 index 00000000000..e8e00f07c22 --- /dev/null +++ b/conf/as3/templates/ModelObject.st @@ -0,0 +1,29 @@ +package $packageName$ { + +$imports:{ import | +import $import$; +}$ + + /** + * $model.description$ + * NOTE: This class is auto generated by the drive code generator program so please do not edit the class manually. + * @author deepak + * + */ + public class $className$ extends $extends$ { + + $fields:{ field | + + /** + * $field.description$ + * $if(field.required)$@Required$endif$ + * $if(field.allowableValues)$[AllowableValues(value="$field.allowedValuesString$"]$endif$ + */ +$if(!field.fieldDefinition.collectionItemType)$ + [XmlElement(name="$field.fieldDefinition.name$")]$endif$ +$if(field.fieldDefinition.collectionItemType)$ + [XmlElements(name="$field.fieldDefinition.name$", type="$field.fieldDefinition.collectionItemType$")]$endif$ + public var $field.fieldDefinition.name$: $field.fieldDefinition.returnType$ $field.fieldDefinition.initialization$;$\r$}$ + + } +} \ No newline at end of file diff --git a/conf/as3/templates/ResourceObject.st b/conf/as3/templates/ResourceObject.st new file mode 100644 index 00000000000..20ae8ce82a2 --- /dev/null +++ b/conf/as3/templates/ResourceObject.st @@ -0,0 +1,111 @@ +package $packageName$ { + + +import $exceptionPackageName$.ApiErrorCodes; +import $exceptionPackageName$.ApiError; +import $modelPackageName$.*; + + +$imports:{ import | +import $import$; +}$ + + /** + * NOTE: This class is auto generated by the drive code generator program so please do not edit the class manually. + * @author deepak + * + */ + public class $resource$ extends $extends$ { + + /** + * Constructor for the $resource$ api client + * @param apiCredentials Wrapper object for tokens and hostName required towards authentication + * @param eventDispatcher Optional event dispatcher that when provided is used by the SDK to dispatch any Response + */ + public function $resource$(apiCredentials: ApiUserCredentials, eventDispatcher: EventDispatcher = null) { + super(apiCredentials, eventDispatcher); + } + + +$methods:{ method | + /** + * $method.description$ +$method.arguments:{ argument | + * @param $argument.name$ $argument.description$ + $if(argument.allowedValues)$ + * Allowed values are - $argument.allowedValues$ + $endif$}$ + * +$if(!method.responseVoid)$ + * @return $method.returnValue$ {@link $method.returnClassName$} $endif$ + */ +$if(method.hasArguments)$ + [MethodArgumentNames(value="$method.argumentNames; separator=", "$")]$endif$ + public function $method.name$($method.argumentDefinitions; separator=", "$): String { + +$if(method.authToken)$ + if(authToken == null || authToken.length == 0) { + throw new ApiError(ApiErrorCodes.AUTH_TOKEN_NOT_VALID); + }$endif$ + var requestId: String = getUniqueId(); + //parse inputs + var resourcePath: String = "$method.resourcePath$"; + resourcePath = resourcePath.replace("{format}","xml"); + var method: String = "$method.methodType$"; + var queryParams:Dictionary = new Dictionary(); +$if(!method.inputModel)$ +$method.queryParameters:{ argument | + if( $argument.name$ != null) { + queryParams["$argument.name$"] = toPathValue($argument.name$); + } +}$ +$method.pathParameters:{ argument | + if( $argument.name$ != null) { + resourcePath = resourcePath.replace("{$argument.name$}", $argument.name$); + } +}$ +$endif$ +$if(method.inputModel)$ +$method.queryParameters:{ argument | + if( $argument.inputModelClassArgument$ != null && $argument.methodNameFromModelClass$ != null) { + queryParams["$argument.name$"] = $argument.methodNameFromModelClass$; + } +}$ +$method.pathParameters:{ argument | + if( $argument.inputModelClassArgument$ != null && $argument.methodNameFromModelClass$ != null) { + resourcePath = resourcePath.replace("{$argument.name$}", $argument.methodNameFromModelClass$); + } +}$ +$endif$ + //make the API Call +$if(method.postObject)$ +$if(method.authToken)$ + var token:AsyncToken = getApiInvoker().invokeAPI(authToken, resourcePath, method, queryParams, postData); +$endif$ +$if(!method.authToken)$ + var token:AsyncToken = getApiInvoker().invokeAPI(null, resourcePath, method, queryParams, postData); +$endif$ +$endif$ + +$if(!method.postObject)$ +$if(method.authToken)$ + var token:AsyncToken = getApiInvoker().invokeAPI(authToken, resourcePath, method, queryParams, null); +$endif$ +$if(!method.authToken)$ + var token:AsyncToken = getApiInvoker().invokeAPI(null, resourcePath, method, queryParams, null); +$endif$ +$endif$ + + token.requestId = requestId; + token.completionEventType = "$method.name$"; + + //create output objects if the response has more than one object +$if(!method.responseVoid)$ + token.returnType = $method.returnClassName$; + +$endif$ + return requestId; + } +}$ + } +} diff --git a/conf/as3/templates/VersionChecker.st b/conf/as3/templates/VersionChecker.st new file mode 100644 index 00000000000..76fc590418a --- /dev/null +++ b/conf/as3/templates/VersionChecker.st @@ -0,0 +1,20 @@ +package $packageName$ { + +/** + * Maintains the compatible server version against which the drive is written + * @author deepak + * + */ + public class VersionChecker { + + private var compatibleVersion: String = "$apiVersion$"; + + /** + * Gets the version against which the driver code was written + */ + public function getCompatibleVersion(): String { + return compatibleVersion; + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/wordnik/swagger/codegen/FieldDefinition.java b/src/main/java/com/wordnik/swagger/codegen/FieldDefinition.java index 615e24fe5cf..c357d0b6feb 100644 --- a/src/main/java/com/wordnik/swagger/codegen/FieldDefinition.java +++ b/src/main/java/com/wordnik/swagger/codegen/FieldDefinition.java @@ -28,6 +28,8 @@ public class FieldDefinition { private String initialization; private List importDefinitions = new ArrayList(); + + private String collectionItemType; public String getReturnType() { return returnType; @@ -61,5 +63,11 @@ public class FieldDefinition { return name.substring(0,1).toUpperCase() + name.substring(1); } + public void setCollectionItemType(String collectionItemType) { + this.collectionItemType = collectionItemType; + } + public String getCollectionItemType() { + return collectionItemType; + } } diff --git a/src/main/java/com/wordnik/swagger/codegen/LibraryCodeGenerator.java b/src/main/java/com/wordnik/swagger/codegen/LibraryCodeGenerator.java index 622966190ae..540b081d001 100644 --- a/src/main/java/com/wordnik/swagger/codegen/LibraryCodeGenerator.java +++ b/src/main/java/com/wordnik/swagger/codegen/LibraryCodeGenerator.java @@ -106,7 +106,13 @@ public class LibraryCodeGenerator { } generateModelClasses(resources, aTemplateGroup); generateModelClassesForInput(resources, aTemplateGroup); - generateEnumForAllowedValues(resources, aTemplateGroup); + if(languageConfig.isGenerateHelperEnums()){ + generateEnumForAllowedValues(resources, aTemplateGroup); + } + + if(languageConfig.isGenerateOutputWrappers()) { + generateOutputWrappers(resources, aTemplateGroup); + } generateAPIClasses(resources, aTemplateGroup); } @@ -139,7 +145,7 @@ public class LibraryCodeGenerator { List imports = new ArrayList(); imports.addAll(this.config.getDefaultModelImports()); for(ModelField param : model.getFields()){ - for(String importDef : param.getFieldDefinition(this.getDataTypeMappingProvider()).getImportDefinitions()){ + for(String importDef : param.getFieldDefinition(this.getDataTypeMappingProvider(), config, nameGenerator).getImportDefinitions()){ if(!imports.contains(importDef)){ imports.add(importDef); } @@ -182,7 +188,7 @@ public class LibraryCodeGenerator { List imports = new ArrayList(); imports.addAll(this.config.getDefaultModelImports()); for(ModelField param : model.getFields()){ - for(String importDef : param.getFieldDefinition(this.getDataTypeMappingProvider()).getImportDefinitions()){ + for(String importDef : param.getFieldDefinition(this.getDataTypeMappingProvider(), config, nameGenerator).getImportDefinitions()){ if(!imports.contains(importDef)){ imports.add(importDef); } @@ -265,6 +271,57 @@ public class LibraryCodeGenerator { } } + private void generateOutputWrappers(List resources, StringTemplateGroup templateGroup) { + List generatedClasses = new ArrayList(); + StringTemplate template; + + for(Resource resource: resources) { + if(resource.getEndPoints() != null) { + for(Endpoint endpoint : resource.getEndPoints()){ + if(endpoint.getOperations() != null) { + for(EndpointOperation operation : endpoint.getOperations()){ + ResourceMethod method = operation.generateMethod(endpoint, resource, dataTypeMappingProvider, nameGenerator); + if(codeGenRulesProvider.isModelIgnored( nameGenerator.applyMethodNamingPolicy( method.getReturnClassName() ))){ + continue; + } + if(method.getOutputWrapperModel() != null) { + Model model = method.getOutputWrapperModel(); + method.setReturnClassName(model.getName()); + if(model != null){ + if(!generatedClasses.contains(model.getName())) { + List imports = new ArrayList(); + imports.addAll(this.config.getDefaultModelImports()); + for(ModelField param : model.getFields()){ + for(String importDef : param.getFieldDefinition(this.getDataTypeMappingProvider(), config, nameGenerator).getImportDefinitions()){ + if(!imports.contains(importDef)){ + imports.add(importDef); + } + } + } + template = templateGroup.getInstanceOf(MODEL_OBJECT_TEMPLATE); + + template.setAttribute("fields", model.getFields()); + template.setAttribute("imports", imports); + template.setAttribute("extends", config.getDefaultModelBaseClass()); + template.setAttribute("annotationPackageName", languageConfig.getAnnotationPackageName()); + template.setAttribute("className", model.getGenratedClassName()); + template.setAttribute(PACKAGE_NAME, config.getModelPackageName()); + File aFile = new File(languageConfig.getModelClassLocation()+model.getGenratedClassName()+languageConfig.getClassFileExtension()); + writeFile(aFile, template.toString(), "Output wrapper model class"); + generatedClasses.add(model.getName()); + } + } + } + + } + } + } + } + } + + + } + /** * Generates one API class for each resource and each end point in the resource is translated as method. * @param resources @@ -328,7 +385,7 @@ public class LibraryCodeGenerator { imports.addAll(this.config.getDefaultModelImports()); imports.addAll(this.getDataTypeMappingProvider().getListIncludes()); for(ModelField param : model.getFields()){ - for(String importDef : param.getFieldDefinition(this.getDataTypeMappingProvider()).getImportDefinitions()){ + for(String importDef : param.getFieldDefinition(this.getDataTypeMappingProvider(), config, nameGenerator).getImportDefinitions()){ if(!imports.contains(importDef)){ imports.add(importDef); } diff --git a/src/main/java/com/wordnik/swagger/codegen/ResourceMethod.java b/src/main/java/com/wordnik/swagger/codegen/ResourceMethod.java index 151479de00f..f8b551f998f 100644 --- a/src/main/java/com/wordnik/swagger/codegen/ResourceMethod.java +++ b/src/main/java/com/wordnik/swagger/codegen/ResourceMethod.java @@ -53,7 +53,8 @@ public class ResourceMethod { private boolean postObject; private Model inputModel; - + + private Model outputWrapperModel; public String getTitle() { return title; @@ -200,4 +201,12 @@ public class ResourceMethod { } return false; } + + public void setOutputWrapperModel(Model outputWrapperModel) { + this.outputWrapperModel = outputWrapperModel; + } + + public Model getOutputWrapperModel() { + return outputWrapperModel; + } } diff --git a/src/main/java/com/wordnik/swagger/codegen/config/DataTypeMappingProvider.java b/src/main/java/com/wordnik/swagger/codegen/config/DataTypeMappingProvider.java index 947e5397128..db7ddc3d3f7 100644 --- a/src/main/java/com/wordnik/swagger/codegen/config/DataTypeMappingProvider.java +++ b/src/main/java/com/wordnik/swagger/codegen/config/DataTypeMappingProvider.java @@ -187,4 +187,14 @@ public interface DataTypeMappingProvider { * @return */ public String getGenericType(String type); + + /** + * Returns the syntax for defintion of an object of type and name + * + * @param argumentType + * @param argumentName + * @return + */ + public String getArgumentDefinition(String argumentType, String argumentName); + } diff --git a/src/main/java/com/wordnik/swagger/codegen/config/LanguageConfiguration.java b/src/main/java/com/wordnik/swagger/codegen/config/LanguageConfiguration.java index 57bdf721088..a70dbbb16d0 100644 --- a/src/main/java/com/wordnik/swagger/codegen/config/LanguageConfiguration.java +++ b/src/main/java/com/wordnik/swagger/codegen/config/LanguageConfiguration.java @@ -41,6 +41,10 @@ public class LanguageConfiguration { private String annotationPackageName; + private boolean generateHelperEnums = true; + + private boolean generateOutputWrappers = false; + public String getClassFileExtension() { return classFileExtension; } @@ -109,4 +113,20 @@ public class LanguageConfiguration { public void setLibraryHome(String libraryHome) { this.libraryHome = libraryHome; } + + public void setGenerateHelperEnums(boolean generateHelperEnums) { + this.generateHelperEnums = generateHelperEnums; + } + + public boolean isGenerateHelperEnums() { + return generateHelperEnums; + } + + public void setGenerateOutputWrappers(boolean generateOutputWrappers) { + this.generateOutputWrappers = generateOutputWrappers; + } + + public boolean isGenerateOutputWrappers() { + return generateOutputWrappers; + } } diff --git a/src/main/java/com/wordnik/swagger/codegen/config/NamingPolicyProvider.java b/src/main/java/com/wordnik/swagger/codegen/config/NamingPolicyProvider.java index b85b0042256..185dfac8d1d 100644 --- a/src/main/java/com/wordnik/swagger/codegen/config/NamingPolicyProvider.java +++ b/src/main/java/com/wordnik/swagger/codegen/config/NamingPolicyProvider.java @@ -97,6 +97,18 @@ public interface NamingPolicyProvider { */ public String getInputObjectName(String serviceName, String resourcePath); + /** + * Generate the name of the wrapper class used as a wrapper for a list of items returned by a service + * + * Example: get definitions API returns a list of definition objects as the result. This will be wrapped by an + * object. The object's name will be determined by invoking this service. + * eg. DefinitionList for a wrapper of 'definition's + * + * @param wrapperItemName + * @return + */ + public String getOutputWrapperName(String wrapperItemName); + /** * Generates a name for an enum for the param or field name. * diff --git a/src/main/java/com/wordnik/swagger/codegen/config/as3/As3DataTypeMappingProvider.java b/src/main/java/com/wordnik/swagger/codegen/config/as3/As3DataTypeMappingProvider.java new file mode 100644 index 00000000000..045749d6833 --- /dev/null +++ b/src/main/java/com/wordnik/swagger/codegen/config/as3/As3DataTypeMappingProvider.java @@ -0,0 +1,185 @@ +package com.wordnik.swagger.codegen.config.as3; + +import com.wordnik.swagger.codegen.config.DataTypeMappingProvider; +import com.wordnik.swagger.codegen.config.NamingPolicyProvider; +import com.wordnik.swagger.codegen.config.common.CamelCaseNamingPolicyProvider; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * User: ramesh + * Date: 5/31/11 + * Time: 7:03 AM + */ +public class As3DataTypeMappingProvider implements DataTypeMappingProvider { + + public static Map primitiveValueMap = new HashMap(); + static{ + primitiveValueMap.put("string", "String"); + primitiveValueMap.put("String", "String"); + primitiveValueMap.put("int", "Number"); + primitiveValueMap.put("integer", "int"); + primitiveValueMap.put("Integer", "int"); + primitiveValueMap.put("boolean", "Boolean"); + primitiveValueMap.put("Boolean", "Boolean"); + primitiveValueMap.put("long", "Number"); + primitiveValueMap.put("Long", "Number"); + primitiveValueMap.put("double", "Number"); + primitiveValueMap.put("Double", "Number"); + primitiveValueMap.put("float", "Number"); + primitiveValueMap.put("Float", "Number"); + primitiveValueMap.put("Date", "Date"); + primitiveValueMap.put("date", "Date"); + } + + public static Map primitiveObjectMap = new HashMap(); + static{ + primitiveObjectMap.put("string", "String"); + primitiveObjectMap.put("String", "String"); + primitiveObjectMap.put("int", "int"); + primitiveObjectMap.put("integer", "int"); + primitiveObjectMap.put("Integer", "int"); + primitiveObjectMap.put("boolean", "Boolean"); + primitiveObjectMap.put("Boolean", "Boolean"); + primitiveObjectMap.put("long", "Number"); + primitiveObjectMap.put("Long", "Number"); + primitiveObjectMap.put("double", "Number"); + primitiveObjectMap.put("Double", "Number"); + primitiveObjectMap.put("float", "Number"); + primitiveObjectMap.put("Float", "Number"); + primitiveObjectMap.put("Date", "Date"); + primitiveObjectMap.put("date", "Date"); + } + + private NamingPolicyProvider nameGenerator = new CamelCaseNamingPolicyProvider(); + + public boolean isPrimitiveType(String type) { + if(type.equalsIgnoreCase("String") || type.equalsIgnoreCase("int") || type.equalsIgnoreCase("integer") || type.equalsIgnoreCase("double") || + type.equalsIgnoreCase("boolean") || type.equalsIgnoreCase("float")|| type.equalsIgnoreCase("long") || type.equalsIgnoreCase("Number") ){ + return true; + } + return false; + } + + /** + * If the data type is primitive and it is expecting object structure then return primitive objects + * else return primitive types + * @param type + * @param primitiveObject -- indicates if the object is primitive or not + * @return + */ + public String getObjectType(String type, boolean primitiveObject) { + if(isPrimitiveType(type)){ + if(primitiveObject){ + return primitiveObjectMap.get(type); + }else{ + return primitiveValueMap.get(type); + } + }else{ + return nameGenerator.applyClassNamingPolicy(type); + } + } + + public String getListReturnTypeSignature(String typeClass) { + return "Array"; + } + + public String getReturnTypeForVoidMethods() { + return "void"; + } + + public String getMapReturnTypeSignature(String typeClass) { + return "Object"; + } + + public String getSetReturnTypeSignature(String typeClass) { + return "Array"; + } + + public String generateListInitialization(String typeClass) { + return " new Array()"; + } + + public String generateMapInitialization(String typeClass) { + return " new Object()"; + } + + public String generateSetInitialization(String typeClass) { + return " new Array()"; + } + + public List getListIncludes() { + List imports = new ArrayList(); + return imports; + } + + public List getMapIncludes() { + List imports = new ArrayList(); + imports.add("flash.utils.Dictionary"); + return imports; + } + + public List getSetIncludes() { + List imports = new ArrayList(); + return imports; } + + + public List getDateIncludes() { + List imports = new ArrayList(); + return imports; + } + + /** + * Gets the short name of the class the class. + * Input can be MAP, LIST or regular string. In case of map or list the class name will be class name + * that map or list is returning. + * @param type + * @return + */ + public String getClassType(String type, boolean primitiveObject) { + String classShortName = ""; + if(type.startsWith("List[")){ + classShortName = type.substring(5, type.length()-1); + classShortName = getObjectType(classShortName, true); + }else if (type.startsWith("Map[")) { + classShortName = type.substring(4, type.length()-1); + classShortName = getObjectType(classShortName, true); + }else if (type.startsWith("Set[")) { + classShortName = type.substring(4, type.length()-1); + classShortName = getObjectType(classShortName, true); + }else if (type.equals("ok")) { + classShortName = "void"; + }else{ + classShortName = getObjectType(type, true); + } + return classShortName; + } + + public String getArgumentDefinition(String argumentType, String argumentName) { + return argumentName + ": " + argumentType; + } + + /** + * Gets the class of the expected return value for a type string. Examples of type Strings are int, User, List[User] + * If the type string is a collection type like a map or list the string value returned would be the class + * that map or list is returning. + * + * @param type + * @return + */ + public String getGenericType(String type) { + if(type.equalsIgnoreCase("void")|| type.equalsIgnoreCase("ok")){ + return "void"; + } + String classShortName = ""; + if(type.startsWith("List[") || type.startsWith("Map[") || type.startsWith("Set[")){ + classShortName = "Array"; + }else{ + classShortName = getObjectType(type, true); + } + return classShortName; + } +} diff --git a/src/main/java/com/wordnik/swagger/codegen/config/as3/As3LibCodeGen.java b/src/main/java/com/wordnik/swagger/codegen/config/as3/As3LibCodeGen.java new file mode 100644 index 00000000000..473bb03ff21 --- /dev/null +++ b/src/main/java/com/wordnik/swagger/codegen/config/as3/As3LibCodeGen.java @@ -0,0 +1,85 @@ +package com.wordnik.swagger.codegen.config.as3; + +import com.wordnik.swagger.codegen.LibraryCodeGenerator; +import com.wordnik.swagger.codegen.config.LanguageConfiguration; +import com.wordnik.swagger.codegen.config.common.CamelCaseNamingPolicyProvider; +import com.wordnik.swagger.codegen.exception.CodeGenerationException; +import com.wordnik.swagger.codegen.util.FileUtil; + +import java.io.File; + +/** + * User: deepakmichael + * Date: 17/08/11 + * Time: 5:02 PM + */ +public class As3LibCodeGen extends LibraryCodeGenerator{ + public static void main(String[] args) { + if(args.length < 1){ + throw new CodeGenerationException("Invalid number of arguments passed: No command line argument was passed to the program for config json"); + } + if(args.length == 1) { + String configPath = args[0]; + As3LibCodeGen codeGenerator = new As3LibCodeGen(configPath); + codeGenerator.generateCode(); + } + if(args.length == 4) { + String apiServerURL = args[0]; + if(!apiServerURL.endsWith("/")){ + apiServerURL = apiServerURL + "/"; + } + String apiKey = args[1]; + String packageName = args[2]; + String libraryHome = args[3]; + if(libraryHome.endsWith("/")){ + libraryHome = libraryHome.substring(0, libraryHome.length()-1); + } + String modelPackageName = packageName+".model"; + String apiPackageName = packageName+".api"; + String classOutputDir = libraryHome + "/src/main/as3/" + packageName.replace(".","/"); + As3LibCodeGen codeGenerator = new As3LibCodeGen(apiServerURL, apiKey, modelPackageName, + apiPackageName, classOutputDir, libraryHome); + codeGenerator.generateCode(); + } + + } + + public As3LibCodeGen(String apiServerURL, String apiKey, String modelPackageName, String apiPackageName, + String classOutputDir, String libraryHome){ + super(apiServerURL, apiKey, modelPackageName, apiPackageName, classOutputDir, libraryHome); + this.setDataTypeMappingProvider(new As3DataTypeMappingProvider()); + this.setNameGenerator(new As3NamingPolicyProvider()); + } + + public As3LibCodeGen(String configPath){ + super(configPath); + this.setDataTypeMappingProvider(new As3DataTypeMappingProvider()); + this.setNameGenerator(new As3NamingPolicyProvider()); + } + + @Override + protected LanguageConfiguration initializeLangConfig(LanguageConfiguration as3Configuration) { + as3Configuration.setClassFileExtension(".as"); + as3Configuration.setTemplateLocation("conf/as3/templates"); + as3Configuration.setStructureLocation("conf/as3/structure"); + as3Configuration.setExceptionPackageName("com.wordnik.swagger.exception"); + as3Configuration.setAnnotationPackageName("com.wordnik.swagger.annotations"); + + //create ouput directories + FileUtil.createOutputDirectories(as3Configuration.getModelClassLocation(), as3Configuration.getClassFileExtension()); + FileUtil.createOutputDirectories(as3Configuration.getResourceClassLocation(), as3Configuration.getClassFileExtension()); +/* + FileUtil.clearFolder(as3Configuration.getLibraryHome() + "/src/main/java/com/wordnik/swagger/runtime"); + FileUtil.createOutputDirectories(as3Configuration.getLibraryHome() + "/src/main/java/com/wordnik/swagger/runtime", "as"); +*/ + FileUtil.clearFolder(as3Configuration.getLibraryHome() + "/src/main/as3/com/wordnik/swagger/common"); + FileUtil.clearFolder(as3Configuration.getLibraryHome() + "/src/main/as3/com/wordnik/swagger/exception"); + FileUtil.clearFolder(as3Configuration.getLibraryHome() + "/src/main/as3/com/wordnik/swagger/event"); + FileUtil.copyDirectory(new File(as3Configuration.getStructureLocation()), new File(as3Configuration.getLibraryHome())); + + as3Configuration.setGenerateHelperEnums(false); + as3Configuration.setGenerateOutputWrappers(true); + return as3Configuration; + } + +} diff --git a/src/main/java/com/wordnik/swagger/codegen/config/as3/As3NamingPolicyProvider.java b/src/main/java/com/wordnik/swagger/codegen/config/as3/As3NamingPolicyProvider.java new file mode 100644 index 00000000000..165940e7867 --- /dev/null +++ b/src/main/java/com/wordnik/swagger/codegen/config/as3/As3NamingPolicyProvider.java @@ -0,0 +1,25 @@ +package com.wordnik.swagger.codegen.config.as3; + +import com.wordnik.swagger.codegen.config.common.CamelCaseNamingPolicyProvider; + +/** + * User: deepakmichael + * Date: 16/08/11 + * Time: 11:01 AM + */ +public class As3NamingPolicyProvider extends CamelCaseNamingPolicyProvider { + + /** + * Gets the signature of the method that gets value for give attribute name. + * + * Example: If class name is user and attibute name is email the out in java language will be + * user.getEmail() + * + * @param className + * @param attributeName + * @return + */ + public String createGetterMethodName(String className, String attributeName) { + return className+"."+ attributeName; + } +} diff --git a/src/main/java/com/wordnik/swagger/codegen/config/common/CamelCaseNamingPolicyProvider.java b/src/main/java/com/wordnik/swagger/codegen/config/common/CamelCaseNamingPolicyProvider.java index 42204c545a3..a4663f412c6 100644 --- a/src/main/java/com/wordnik/swagger/codegen/config/common/CamelCaseNamingPolicyProvider.java +++ b/src/main/java/com/wordnik/swagger/codegen/config/common/CamelCaseNamingPolicyProvider.java @@ -141,6 +141,20 @@ public class CamelCaseNamingPolicyProvider implements NamingPolicyProvider { return inputobjectName; } + /** + * Generate the name of the wrapper class used as a wrapper for a list of items returned by a service + *

+ * Example: get definitions API returns a list of definition objects as the result. This will be wrapped by an + * object. The object's name will be determined by invoking this service. + * eg. DefinitionList for a wrapper of 'definition's + * + * @param wrapperItemName + * @return + */ + public String getOutputWrapperName(String wrapperItemName) { + return applyClassNamingPolicy(wrapperItemName) + "Wrapper"; + } + /** * Generates a name for an enum for the param or field name. *

diff --git a/src/main/java/com/wordnik/swagger/codegen/config/java/JavaDataTypeMappingProvider.java b/src/main/java/com/wordnik/swagger/codegen/config/java/JavaDataTypeMappingProvider.java index f34ae08d5d0..bd0eafd351e 100644 --- a/src/main/java/com/wordnik/swagger/codegen/config/java/JavaDataTypeMappingProvider.java +++ b/src/main/java/com/wordnik/swagger/codegen/config/java/JavaDataTypeMappingProvider.java @@ -158,7 +158,18 @@ public class JavaDataTypeMappingProvider implements DataTypeMappingProvider { return classShortName; } - /** + /** + * Returns the syntax for defintion of an object of type and name + * + * @param argumentType + * @param argumentName + * @return + */ + public String getArgumentDefinition(String argumentType, String argumentName) { + return argumentType + " " + argumentName; + } + + /** * Gets the class of the expected return value for a type string. Examples of type Strings are int, User, List[User] * If the type string is a collection type like a map or list the string value returned would be the class * that map or list is returning. diff --git a/src/main/java/com/wordnik/swagger/codegen/resource/EndpointOperation.java b/src/main/java/com/wordnik/swagger/codegen/resource/EndpointOperation.java index 761fd112faa..a83fb3ae8e2 100644 --- a/src/main/java/com/wordnik/swagger/codegen/resource/EndpointOperation.java +++ b/src/main/java/com/wordnik/swagger/codegen/resource/EndpointOperation.java @@ -291,7 +291,7 @@ public class EndpointOperation { if (method.getArguments() != null && method.getArguments().size() > 0) { for(MethodArgument arg: method.getArguments()) { if(!arg.getName().equalsIgnoreCase(FORMAT_PARAM_NAME)){ - argumentDefinitions.add(arg.getDataType() + " " + arg.getName()); + argumentDefinitions.add( dataTypeMapper.getArgumentDefinition(arg.getDataType(), arg.getName()) ); argumentNames.add(arg.getName()); } } @@ -306,7 +306,21 @@ public class EndpointOperation { method.setReturnValue(dataTypeMapper.getClassType(responseClass, false)); method.setReturnClassName(dataTypeMapper.getGenericType(responseClass)); - + //if this is a list return type + if(method.getReturnClassName().equals(dataTypeMapper.getListReturnTypeSignature(responseClass))){ + String returnValueTypeName = method.getReturnValue(); + Model outputWrapperModel = new Model(); + outputWrapperModel.setName(nameGenerator.getOutputWrapperName(returnValueTypeName)); + List fields = new ArrayList(); + ModelField aModelField = new ModelField(); + aModelField.setName(nameGenerator.applyMethodNamingPolicy(returnValueTypeName)); + aModelField.setParamType(responseClass); + fields.add(aModelField); + outputWrapperModel.setFields(fields); + method.setOutputWrapperModel(outputWrapperModel); + //method.setReturnClassName(outputWrapperModel.getName()); + } + //get description string for exception method.setExceptionDescription(calculateExceptionMessage()); } diff --git a/src/main/java/com/wordnik/swagger/codegen/resource/ModelField.java b/src/main/java/com/wordnik/swagger/codegen/resource/ModelField.java index a23d1ef29aa..3b9107eb5b7 100644 --- a/src/main/java/com/wordnik/swagger/codegen/resource/ModelField.java +++ b/src/main/java/com/wordnik/swagger/codegen/resource/ModelField.java @@ -17,7 +17,9 @@ package com.wordnik.swagger.codegen.resource; import com.wordnik.swagger.codegen.FieldDefinition; +import com.wordnik.swagger.codegen.config.ApiConfiguration; import com.wordnik.swagger.codegen.config.DataTypeMappingProvider; +import com.wordnik.swagger.codegen.config.NamingPolicyProvider; import java.util.ArrayList; import java.util.List; @@ -170,7 +172,7 @@ public class ModelField { return fieldDefinition; } - public FieldDefinition getFieldDefinition(DataTypeMappingProvider dataTypeMapper) { + public FieldDefinition getFieldDefinition(DataTypeMappingProvider dataTypeMapper, ApiConfiguration config, NamingPolicyProvider nameGenerator) { if(fieldDefinition == null) { fieldDefinition = new FieldDefinition(); String type = paramType.trim(); @@ -180,6 +182,11 @@ public class ModelField { if(type.startsWith("List[")){ fieldDefinition.getImportDefinitions().addAll(dataTypeMapper.getListIncludes()); String entryType = type.substring(5, type.length()-1); + if (dataTypeMapper.isPrimitiveType(entryType)) { + fieldDefinition.setCollectionItemType(entryType); + } else { + fieldDefinition.setCollectionItemType(config.getModelPackageName() + "." + nameGenerator.applyClassNamingPolicy(entryType)); + } entryType = dataTypeMapper.getClassType(entryType, true); String returnType = dataTypeMapper.getListReturnTypeSignature(entryType); fieldDefinition.setReturnType(returnType);