diff --git a/.gitignore b/.gitignore
index e676162d04f..65c86663fdf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,28 +1,7 @@
-java/wordnik*.zip
-java/*.ipr
-java/*.iml
-java/*.iws
-java/dist/
-java/build/
-java/lib/*.jar
-java/META-INF/
-java/web/
-java/index
-java/reports/
-java/lib/*.zip
-java/logs
-java/src/main/java/com/wordnik/env/Version.scala
-java/lib/*.pom
-java/version.properties
-java/out
-android/codegen/build/
*.iml
out/
*.ipr
*.iws
version.properties
-android/codegen/lib/
-android/driver/lib/
-android/driver/build/
-android/driver-test/build/
-android/driver-test/lib/*.jar
+lib/*
+build/*
\ No newline at end of file
diff --git a/bin/runjava.sh b/bin/runjava.sh
new file mode 100755
index 00000000000..ad6d8a172a3
--- /dev/null
+++ b/bin/runjava.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+echo "" > classpath.txt
+for file in `ls lib`;
+ do echo -n 'lib/' >> classpath.txt;
+ echo -n $file >> classpath.txt;
+ echo -n ':' >> classpath.txt;
+done
+for file in `ls build`;
+ do echo -n 'build/' >> classpath.txt;
+ echo -n $file >> classpath.txt;
+ echo -n ':' >> classpath.txt;
+done
+
+export CLASSPATH=$(cat classpath.txt)
+export JAVA_OPTS="${JAVA_OPTS} -DrulePath=data -Dproperty=Xmx2g -DloggerPath=$BUILD_COMMON/test-config/log4j.properties"
+java $WORDNIK_OPTS $JAVA_CONFIG_OPTIONS $JAVA_OPTS -cp $CLASSPATH "$@"
+
diff --git a/bin/runscala.sh b/bin/runscala.sh
new file mode 100755
index 00000000000..454db86c955
--- /dev/null
+++ b/bin/runscala.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+echo "" > classpath.txt
+for file in `ls lib`;
+ do echo -n 'lib/' >> classpath.txt;
+ echo -n $file >> classpath.txt;
+ echo -n ':' >> classpath.txt;
+done
+for file in `ls build`;
+ do echo -n 'build/' >> classpath.txt;
+ echo -n $file >> classpath.txt;
+ echo -n ':' >> classpath.txt;
+done
+
+export CLASSPATH=$(cat classpath.txt)
+export JAVA_OPTS="${JAVA_OPTS} -DrulePath=data -Dproperty=Xmx2g -DloggerPath=$BUILD_COMMON/test-config/log4j.properties"
+scala $WORDNIK_OPTS $JAVA_CONFIG_OPTIONS $JAVA_OPTS -cp $CLASSPATH "$@"
+
diff --git a/build.xml b/build.xml
new file mode 100644
index 00000000000..5ede0f39312
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must specify the parameters: outputPath and apiServerRootDir eg. -DoutputPath=../../api-server-lib/java/src/main/java/com/wordnik/
+ -DapiServerRootDir=../../api-server-lib/java/
+ These are the output path of the Apis and the root directory that will be created for the api server (directory where structure is created)
+
+
+
+
+ outputPath for Api = ${outputPath}
+
+
+ apiServerRootDir = ${apiServerRootDir}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/java/structure/build.xml b/conf/java/structure/build.xml
new file mode 100644
index 00000000000..af23a0a1d32
--- /dev/null
+++ b/conf/java/structure/build.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/java/structure/ivy.xml b/conf/java/structure/ivy.xml
new file mode 100644
index 00000000000..ec44869bb26
--- /dev/null
+++ b/conf/java/structure/ivy.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/java/structure/src/main/java/com/wordnik/swagger/annotations/AllowableValues.java b/conf/java/structure/src/main/java/com/wordnik/swagger/annotations/AllowableValues.java
new file mode 100644
index 00000000000..bc162b068ec
--- /dev/null
+++ b/conf/java/structure/src/main/java/com/wordnik/swagger/annotations/AllowableValues.java
@@ -0,0 +1,19 @@
+package com.wordnik.swagger.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Annotation used to provide list of possible values
+ * @author ramesh
+ *
+ */
+@Target({ElementType.FIELD,ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AllowableValues {
+
+ String value() default "";
+}
diff --git a/conf/java/structure/src/main/java/com/wordnik/swagger/annotations/MethodArgumentNames.java b/conf/java/structure/src/main/java/com/wordnik/swagger/annotations/MethodArgumentNames.java
new file mode 100644
index 00000000000..01aaac0093f
--- /dev/null
+++ b/conf/java/structure/src/main/java/com/wordnik/swagger/annotations/MethodArgumentNames.java
@@ -0,0 +1,13 @@
+package com.wordnik.swagger.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+@Target({ElementType.FIELD,ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MethodArgumentNames {
+ String value() default "";
+}
diff --git a/conf/java/structure/src/main/java/com/wordnik/swagger/annotations/Required.java b/conf/java/structure/src/main/java/com/wordnik/swagger/annotations/Required.java
new file mode 100644
index 00000000000..e3fa6402548
--- /dev/null
+++ b/conf/java/structure/src/main/java/com/wordnik/swagger/annotations/Required.java
@@ -0,0 +1,17 @@
+package com.wordnik.swagger.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation used to indicate given property or field is required or not
+ * @author ramesh
+ *
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Required {
+
+}
diff --git a/conf/java/structure/src/main/java/com/wordnik/swagger/common/StringValue.java b/conf/java/structure/src/main/java/com/wordnik/swagger/common/StringValue.java
new file mode 100644
index 00000000000..4c7eaef40f0
--- /dev/null
+++ b/conf/java/structure/src/main/java/com/wordnik/swagger/common/StringValue.java
@@ -0,0 +1,22 @@
+package com.wordnik.swagger.common;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: ramesh
+ * Date: 4/12/11
+ * Time: 5:46 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class StringValue {
+
+ String word;
+
+
+ public String getWord() {
+ return word;
+ }
+
+ public void setWord(String value) {
+ this.word = value;
+ }
+}
diff --git a/conf/java/structure/src/main/java/com/wordnik/swagger/common/WordnikAPI.java b/conf/java/structure/src/main/java/com/wordnik/swagger/common/WordnikAPI.java
new file mode 100644
index 00000000000..011f1423dbf
--- /dev/null
+++ b/conf/java/structure/src/main/java/com/wordnik/swagger/common/WordnikAPI.java
@@ -0,0 +1,216 @@
+package com.wordnik.swagger.common;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import com.wordnik.swagger.exception.APIException;
+import com.wordnik.swagger.exception.APIExceptionCodes;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.DeserializationConfig.Feature;
+import org.codehaus.jackson.map.SerializationConfig;
+import org.codehaus.jackson.type.TypeReference;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.api.client.WebResource.Builder;
+import com.sun.jersey.api.client.filter.LoggingFilter;
+
+
+/**
+ * Provides way to initialize the communication with Wordnik API server.
+ * This is also a Base class for all API classes
+ * @author ramesh
+ *
+ */
+public class WordnikAPI {
+
+ private static String apiServer = "http://api.wordnik.com/v4";
+ private static String apiKey = "";
+ private static boolean loggingEnabled;
+ private static Logger logger = null;
+
+ protected static String POST = "POST";
+ protected static String GET = "GET";
+ protected static String PUT = "PUT";
+ protected static String DELETE = "DELETE";
+ protected static ObjectMapper mapper = new ObjectMapper();
+ static{
+ mapper.getDeserializationConfig().set(Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ mapper.getSerializationConfig().set(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
+ mapper.configure(SerializationConfig.Feature.WRITE_NULL_PROPERTIES, false);
+ mapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
+ }
+
+ /**
+ * Initializes the API communication with required inputs.
+ * @param apiKey provide the key provided as part of registration
+ * @param apiServer Sets the URL for the API server. It is defaulted to the server
+ * used while building the driver. This value should be provided while testing the APIs against
+ * test servers or if there is any changes in production server URLs.
+ * @param enableLogging This will enable the logging using Jersey logging filter. Refer the following documentation
+ * for more details. {@link com.sun.jersey.api.client.filter.LoggingFilter}. Default output is sent to system.out.
+ * Create a logger ({@link java.util.logging.Logger} class and set using setLogger method.
+ */
+ public static void initialize(String apiKey, String apiServer, boolean enableLogging) {
+ setApiKey(apiKey);
+ if(apiServer != null && apiServer.length() > 0) {
+ if(apiServer.substring(apiServer.length()-1).equals("/")){
+ apiServer = apiServer.substring(0, apiServer.length()-1);
+ }
+ setApiServer(apiServer);
+ }
+ loggingEnabled = enableLogging;
+ }
+
+ /**
+ * Set the logger instance used for Jersey logging.
+ * @param aLogger
+ */
+ public static void setLogger(Logger aLogger) {
+ logger = aLogger;
+ }
+
+ /**
+ * Gets the API key used for server communication.
+ * This value is set using initialize method.
+ * @return
+ */
+ public static String getApiKey() {
+ return apiKey;
+ }
+
+ private static void setApiKey(String apiKey) {
+ WordnikAPI.apiKey = apiKey;
+ }
+
+ /**
+ * Sets the URL for the API server. It is defaulted to the server used while building the driver.
+ * @return
+ */
+ private static String getApiServer() {
+ return apiServer;
+ }
+
+ private static void setApiServer(String server) {
+ WordnikAPI.apiServer = server;
+ }
+
+
+
+ /**
+ * Invokes the API and returns the response as json string.
+ * This is an internal method called by individual APIs for communication. It sets the required HTTP headers
+ * based on API key and auth token.
+ * @param authToken - token that is received as part of authentication call. This is only needed for the calls that are secure.
+ * @param resourceURL - URL for the rest resource
+ * @param method - Method we should use for communicating to the back end.
+ * @param postObject - if the method is POST, provide the object that should be sent as part of post request.
+ * @return JSON response of the API call.
+ * @throws com.wordnik.swagger.exception.APIException if the call to API server fails.
+ */
+ protected static String invokeAPI(String authToken, String resourceURL, String method, Map queryParams, Object postObject) throws APIException {
+
+
+ Client apiClient = Client.create();
+
+ //check for app key and server values
+ if(getApiKey() == null || getApiKey().length() == 0) {
+ String[] args = {getApiKey()};
+ throw new APIException(APIExceptionCodes.API_KEY_NOT_VALID, args);
+ }
+ if(getApiServer() == null || getApiServer().length() == 0) {
+ String[] args = {getApiServer()};
+ throw new APIException(APIExceptionCodes.API_SERVER_NOT_VALID, args);
+ }
+ //initialize the logger if needed
+ if(loggingEnabled) {
+ if(logger == null) {
+ apiClient.addFilter(new LoggingFilter());
+ }else{
+ apiClient.addFilter(new LoggingFilter(logger));
+ }
+ }
+
+ //make the communication
+ resourceURL = getApiServer() + resourceURL;
+ if(queryParams.keySet().size() > 0){
+ int i=0;
+ for(String paramName : queryParams.keySet()){
+ String symbol = "&";
+ if(i==0){
+ symbol = "?";
+ }
+ resourceURL = resourceURL + symbol + paramName + "=" + queryParams.get(paramName);
+ i++;
+ }
+ }
+ WebResource aResource = apiClient.resource(resourceURL);
+ // aResource.queryParams(queryParams);
+
+ //set the required HTTP headers
+ Builder builder = aResource.type("application/json");
+ builder.header("api_key", getApiKey());
+ if(authToken != null){
+ builder.header("auth_token", authToken);
+ }
+ ClientResponse clientResponse = null;
+ if(method.equals(GET)) {
+ clientResponse = builder.get(ClientResponse.class);
+ }else if (method.equals(POST)) {
+ clientResponse = builder.post(ClientResponse.class, serialize(postObject));
+ }else if (method.equals(PUT)) {
+ clientResponse = builder.put(ClientResponse.class, serialize(postObject));
+ }else if (method.equals(DELETE)) {
+ clientResponse = builder.delete(ClientResponse.class);
+ }
+
+ //process the response
+ if(clientResponse.getClientResponseStatus() == ClientResponse.Status.OK) {
+ String response = clientResponse.getEntity(String.class);
+ return response;
+ }else{
+ int responseCode = clientResponse.getClientResponseStatus().getStatusCode() ;
+ throw new APIException(responseCode, clientResponse.getEntity(String.class));
+ }
+ }
+
+ /**
+ * De-serialize the object from String to object of type input class name.
+ * @param response
+ * @param inputClassName
+ * @return
+ */
+ public static Object deserialize(String response, Class inputClassName) throws APIException {
+ try {
+ System.out.println("Input :::::" + response);
+ Object responseObject = mapper.readValue(response, inputClassName);
+ return responseObject;
+ } catch (IOException ioe) {
+ String[] args = new String[]{response, inputClassName.toString()};
+ throw new APIException(APIExceptionCodes.ERROR_CONVERTING_JSON_TO_JAVA, args, "Error in coversting response json value to java object : " + ioe.getMessage(), ioe);
+ }
+ }
+
+
+ /**
+ * serialize the object from String to input object.
+ * @param input
+ * @return
+ */
+ public static String serialize(Object input) throws APIException {
+ try {
+ if(input != null) {
+ return mapper.writeValueAsString(input);
+ }else{
+ return "";
+ }
+ } catch (IOException ioe) {
+ throw new APIException(APIExceptionCodes.ERROR_CONVERTING_JAVA_TO_JSON, "Error in coverting input java to json : " + ioe.getMessage(), ioe);
+ }
+ }
+}
diff --git a/conf/java/structure/src/main/java/com/wordnik/swagger/exception/APIException.java b/conf/java/structure/src/main/java/com/wordnik/swagger/exception/APIException.java
new file mode 100644
index 00000000000..61e98e24326
--- /dev/null
+++ b/conf/java/structure/src/main/java/com/wordnik/swagger/exception/APIException.java
@@ -0,0 +1,84 @@
+package com.wordnik.swagger.exception;
+
+import com.sun.jersey.api.client.ClientResponse;
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonMethod;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * Exception that is thrown if there are any issues in invoking Wordnik API.
+ *
+ * Each exception carries a code and message. Code can be either HTTP error response code {@link com.sun.jersey.api.client.ClientResponse.Status}
+ * or The list of possible Wordnik exception code that are listed in the interface {@link APIExceptionCodes}.
+ * User: ramesh
+ * Date: 3/31/11
+ * Time: 9:27 AM
+ */
+public class APIException extends Exception {
+
+ private String message;
+
+ private int code;
+
+ private String[] args;
+
+ @JsonCreator
+ public APIException() {
+ }
+
+ public APIException(String message) {
+ super(message);
+ }
+
+ public APIException(int code) {
+ this.code = code;
+ }
+
+ public APIException(int code, String message, Throwable t) {
+ super(message, t);
+ this.message = message;
+ this.code = code;
+ }
+
+ public APIException(int code, String[] args, String message, Throwable t) {
+ super(message, t);
+ this.message = message;
+ this.code = code;
+ this.args = args;
+ }
+
+ public APIException(int code, String message) {
+ super(message);
+ this.message = message;
+ this.code = code;
+ }
+
+ public APIException(int code, String[] args, String message) {
+ super(message);
+ this.message = message;
+ this.code = code;
+ this.args = args;
+ }
+
+ public APIException(int code, String[] args) {
+ this.code = code;
+ this.args = args;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ public void setCode(int code) {
+ this.code = code;
+ }
+}
diff --git a/conf/java/structure/src/main/java/com/wordnik/swagger/exception/APIExceptionCodes.java b/conf/java/structure/src/main/java/com/wordnik/swagger/exception/APIExceptionCodes.java
new file mode 100644
index 00000000000..688f7342f98
--- /dev/null
+++ b/conf/java/structure/src/main/java/com/wordnik/swagger/exception/APIExceptionCodes.java
@@ -0,0 +1,38 @@
+package com.wordnik.swagger.exception;
+
+/**
+ * Lists all the possible exception codes
+ * @author ramesh
+ *
+ */
+public interface APIExceptionCodes {
+
+ /**
+ * System exception.
+ */
+ public static final int SYSTEM_EXCEPTION = 0;
+
+ /**
+ * With Arguments as current key.
+ */
+ public static final int API_KEY_NOT_VALID = 1000;
+ /**
+ * With arguments as current token value
+ */
+ public static final int AUTH_TOKEN_NOT_VALID = 1001;
+ /**
+ * With arguments as input JSON and output class anme
+ */
+ public static final int ERROR_CONVERTING_JSON_TO_JAVA = 1002;
+ /**
+ * With arguments as JAVA class name
+ */
+ public static final int ERROR_CONVERTING_JAVA_TO_JSON = 1003;
+
+ public static final int ERROR_FROM_WEBSERVICE_CALL = 1004;
+ /**
+ * With arguments as current API server name
+ */
+ public static final int API_SERVER_NOT_VALID = 1005;
+
+}
diff --git a/conf/java/structure/src/main/java/com/wordnik/swagger/exception/CodeGenerationException.java b/conf/java/structure/src/main/java/com/wordnik/swagger/exception/CodeGenerationException.java
new file mode 100644
index 00000000000..308f4a27338
--- /dev/null
+++ b/conf/java/structure/src/main/java/com/wordnik/swagger/exception/CodeGenerationException.java
@@ -0,0 +1,25 @@
+package com.wordnik.swagger.exception;
+
+/**
+ * Exception raised while generating code for java driver.
+ * User: ramesh
+ * Date: 3/31/11
+ * Time: 9:29 AM
+ */
+public class CodeGenerationException extends RuntimeException {
+
+ private String message;
+
+ public CodeGenerationException(String message){
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
+
diff --git a/conf/java/templates/EnumObject.st b/conf/java/templates/EnumObject.st
new file mode 100644
index 00000000000..9cbc2c661c5
--- /dev/null
+++ b/conf/java/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/java/templates/ModelObject.st b/conf/java/templates/ModelObject.st
new file mode 100644
index 00000000000..75ebd5a1999
--- /dev/null
+++ b/conf/java/templates/ModelObject.st
@@ -0,0 +1,40 @@
+package $packageName$;
+
+import $annotationPackageName$.AllowableValues;
+import $annotationPackageName$.Required;
+
+$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 ramesh
+ *
+ */
+public class $className$ extends $extends$ {
+
+$fields:{ field |
+
+ /**
+ * $field.description$
+ */
+ private $field.fieldDefinition.returnType$ $field.fieldDefinition.name$ $field.fieldDefinition.initialization$;$\r$}$
+
+$fields:{ field |
+ /**
+ * $field.description$
+ * $if(field.required)$@Required$endif$
+ * $if(field.allowableValues)$@AllowableValues(value="$field.allowedValuesString$")$endif$
+ */
+ public $field.fieldDefinition.returnType$ get$field.fieldDefinition.NameForMethod$() {
+ return $field.fieldDefinition.name$;
+ }
+
+ public void set$field.fieldDefinition.NameForMethod$($field.fieldDefinition.returnType$ $field.fieldDefinition.name$) {
+ this.$field.fieldDefinition.name$ = $field.fieldDefinition.name$;
+ }
+
+}$
+}
\ No newline at end of file
diff --git a/conf/java/templates/ResourceObject.st b/conf/java/templates/ResourceObject.st
new file mode 100644
index 00000000000..3887c24b919
--- /dev/null
+++ b/conf/java/templates/ResourceObject.st
@@ -0,0 +1,153 @@
+package $packageName$;
+
+
+import $annotationPackageName$.MethodArgumentNames;
+import $exceptionPackageName$.APIExceptionCodes;
+import $exceptionPackageName$.APIException;
+import $modelPackageName$.*;
+
+import org.codehaus.jackson.map.DeserializationConfig.Feature;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.type.TypeReference;
+
+import java.util.*;
+import java.io.IOException;
+
+$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 ramesh
+ *
+ */
+public class $resource$ extends $extends$ {
+
+$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$
+ * @throws APIException $method.exceptionDescription$
+ */
+$if(method.hasArguments)$
+ @MethodArgumentNames(value="$method.argumentNames; separator=", "$")
+$endif$
+
+ public static $method.returnValue$ $method.name$($method.argumentDefinitions; separator=", "$) throws APIException {
+
+$if(method.authToken)$
+ if(authToken == null || authToken.length() == 0) {
+ throw new APIException(APIExceptionCodes.AUTH_TOKEN_NOT_VALID);
+ }
+$endif$
+
+ //parse inputs
+ String resourcePath = "$method.resourcePath$";
+ resourcePath = resourcePath.replace("{format}","json");
+ String method = "$method.methodType$";
+ Map queryParams = new HashMap();
+$if(!method.inputModel)$
+$method.queryParameters:{ argument |
+ if( $argument.name$ != null) {
+ queryParams.put("$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.put("$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)$
+ String response = invokeAPI(authToken, resourcePath, method, queryParams, postObject);
+$endif$
+$if(!method.authToken)$
+ String response = invokeAPI(null, resourcePath, method, queryParams, postObject);
+$endif$
+$endif$
+
+$if(!method.postObject)$
+$if(method.authToken)$
+ String response = invokeAPI(authToken, resourcePath, method, queryParams, null);
+$endif$
+$if(!method.authToken)$
+ String response = invokeAPI(null, resourcePath, method, queryParams, null);
+$endif$
+$endif$
+
+ //create output objects if the response has more than one object
+$if(!method.responseVoid)$
+ if(response == null || response.length() == 0){
+ return null;
+ }
+$if(!method.returnValueList)$
+ $method.returnValue$ responseObject = ($method.returnValue$)deserialize(response, $method.returnClassName$.class);
+ return responseObject;
+$endif$
+$if(method.returnValueList)$
+ TypeReference> typeRef = new TypeReference>() {
+ };
+ try {
+ List<$method.returnClassName$> responseObject = (List<$method.returnClassName$>) mapper.readValue(response, typeRef);
+ return responseObject;
+ } catch (IOException ioe) {
+ String[] args = new String[]{response, typeRef.toString()};
+ throw new APIException(APIExceptionCodes.ERROR_CONVERTING_JSON_TO_JAVA, args, "Error in converting response json value to java object : " + ioe.getMessage(), ioe);
+ }
+$endif$
+$endif$
+ }
+
+}$
+
+ /**
+ * Overloaded method for returning the path value
+ * For a string value an empty value is returned if the value is null
+ * @param value
+ * @return
+ */
+ private static String toPathValue(String value) {
+ return value == null ? "" : value;
+ }
+
+ /**
+ * Overloaded method for returning a path value
+ * For a list of objects a comma separated string is returned
+ * @param objects
+ * @return
+ */
+ private static String toPathValue(List objects) {
+ StringBuilder out = new StringBuilder();
+ for(Object o: objects){
+ out.append(o.toString());
+ out.append(",");
+ }
+ if(out.indexOf(",") != -1) {
+ return out.substring(0, out.lastIndexOf(",") );
+ }
+ return out.toString();
+ }
+}
diff --git a/conf/java/templates/VersionChecker.st b/conf/java/templates/VersionChecker.st
new file mode 100644
index 00000000000..1044bd190cb
--- /dev/null
+++ b/conf/java/templates/VersionChecker.st
@@ -0,0 +1,18 @@
+package $packageName$;
+
+/**
+ * Maintains the compatible server version against which the drive is written
+ * @author ramesh
+ *
+ */
+public class VersionChecker {
+
+ private String compatibleVersion = "$apiVersion$";
+
+ /**
+ * Gets the version against which the driver code was written
+ */
+ public String getCompatibleVersion() {
+ return compatibleVersion;
+ }
+}
\ No newline at end of file
diff --git a/ivy.xml b/ivy.xml
new file mode 100644
index 00000000000..7a0ee256653
--- /dev/null
+++ b/ivy.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/com/wordnik/swagger/codegen/DriverCodeGenerator.java b/src/main/java/com/wordnik/swagger/codegen/DriverCodeGenerator.java
new file mode 100644
index 00000000000..ff21366d21c
--- /dev/null
+++ b/src/main/java/com/wordnik/swagger/codegen/DriverCodeGenerator.java
@@ -0,0 +1,336 @@
+package com.wordnik.swagger.codegen;
+
+import com.wordnik.swagger.codegen.api.SwaggerResourceDocReader;
+import com.wordnik.swagger.codegen.config.*;
+import com.wordnik.swagger.codegen.config.ApiConfiguration;
+import com.wordnik.swagger.codegen.resource.*;
+import com.wordnik.swagger.exception.CodeGenerationException;
+import org.antlr.stringtemplate.StringTemplate;
+import org.antlr.stringtemplate.StringTemplateGroup;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * User: ramesh
+ * Date: 3/30/11
+ * Time: 6:59 PM
+ */
+public class DriverCodeGenerator {
+
+ private static String VERSION_OBJECT_TEMPLATE = "VersionChecker";
+ private static String MODEL_OBJECT_TEMPLATE = "ModelObject";
+ private static String API_OBJECT_TEMPLATE = "ResourceObject";
+ private static final String ENUM_OBJECT_TEMPLATE = "EnumObject";
+
+ private static final String PACKAGE_NAME = "packageName";
+ private ApiConfiguration config = null;
+ private LanguageConfiguration languageConfig = null;
+
+ private SwaggerResourceDocReader apiMarshaller;
+ protected DataTypeMappingProvider dataTypeMappingProvider;
+ protected RulesProvider codeGenRulesProvider;
+ protected NamingPolicyProvider nameGenerator;
+
+ /**
+ * Generate classes needed for the model and API invocation
+ */
+ public void generateCode() {
+ apiMarshaller = new SwaggerResourceDocReader(this.config, this.getDataTypeMappingProvider(), this.getNameGenerator());
+ //read resources and get their documentation
+ List resources = apiMarshaller.readResourceDocumentation();
+ StringTemplateGroup aTemplateGroup = new StringTemplateGroup("templates", languageConfig.getTemplateLocation());
+ if(resources.size() > 0) {
+ generateVersionHelper(resources.get(0).getApiVersion(), aTemplateGroup);
+ }
+ generateModelClasses(resources, aTemplateGroup);
+ generateModelClassesForInput(resources, aTemplateGroup);
+ generateEnumForAllowedValues(resources, aTemplateGroup);
+ generateAPIClasses(resources, aTemplateGroup);
+ }
+
+ /**
+ * Generates version file based on the version number received from the doc calls. This version file is used
+ * while making the API calls to make sure Client and back end are compatible.
+ * @param version
+ */
+ private void generateVersionHelper(String version, StringTemplateGroup templateGroup) {
+ StringTemplate template = templateGroup.getInstanceOf(VERSION_OBJECT_TEMPLATE);
+ template.setAttribute("apiVersion", version);
+ template.setAttribute(PACKAGE_NAME, config.getApiPackageName());
+ File aFile = new File(languageConfig.getResourceClassLocation() + this.getNameGenerator().getVersionCheckerClassName()
+ + languageConfig.getClassFileExtension());
+ writeFile(aFile, template.toString(), "Version checker class");
+ }
+
+ /**
+ * Generates model classes. If the class is already generated then ignores the same.
+ */
+ private void generateModelClasses(List resources, StringTemplateGroup templateGroup) {
+ List generatedClassNames = new ArrayList();
+
+ for(Resource resource: resources) {
+ for(Model model : resource.getModels()){
+ if(!generatedClassNames.contains(model.getName()) && !this.getCodeGenRulesProvider().isModelIgnored(model.getName())){
+ List imports = new ArrayList();
+ imports.addAll(this.config.getDefaultModelImports());
+ for(ModelField param : model.getFields()){
+ for(String importDef : param.getFieldDefinition(this.getDataTypeMappingProvider()).getImportDefinitions()){
+ if(!imports.contains(importDef)){
+ imports.add(importDef);
+ }
+ }
+ }
+ StringTemplate template = templateGroup.getInstanceOf(MODEL_OBJECT_TEMPLATE);
+ template.setAttribute("fields", model.getFields());
+ template.setAttribute("imports", imports);
+ template.setAttribute("annotationPackageName", languageConfig.getAnnotationPackageName());
+ template.setAttribute("extends", config.getModelBaseClass());
+ 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(), "Model class");
+ generatedClassNames.add(model.getName());
+ }
+ }
+ }
+
+ generateWrapperClassForTestData(generatedClassNames, templateGroup);
+ }
+
+ /**
+ * Generates assembler classes if the API returns more than one objects.
+ * @param resources
+ * @param templateGroup
+ */
+ private void generateModelClassesForInput(List resources, StringTemplateGroup templateGroup) {
+ List generatedClasses = new ArrayList();
+ 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(method.getInputModel() != null) {
+ Model model = method.getInputModel();
+ 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()).getImportDefinitions()){
+ if(!imports.contains(importDef)){
+ imports.add(importDef);
+ }
+ }
+ }
+ StringTemplate template = templateGroup.getInstanceOf(MODEL_OBJECT_TEMPLATE);
+
+ template.setAttribute("fields", model.getFields());
+ template.setAttribute("imports", imports);
+ template.setAttribute("extends", config.getModelBaseClass());
+ 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(), "Input model class");
+ generatedClasses.add(model.getName());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Generates an Enum class for method params that have an allowed values list.
+ * @param resources
+ * @param templateGroup
+ */
+ private void generateEnumForAllowedValues(List resources, StringTemplateGroup templateGroup) {
+ List generatedEnums = new ArrayList();
+ StringTemplate template;
+ String valuePrefix, valueSuffix = "";
+ String enumName;
+ 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, config);
+ if(operation.getParameters() != null){
+ for(ModelField operationParam : operation.getParameters()){
+ //skipping the case where there is just one item - TODO process case of allowableValue like '0 to 1000'
+ if(operationParam.getAllowableValues() != null && operationParam.getAllowableValues().size() > 1) {
+ if(!generatedEnums.contains(operationParam.getName())){
+ //generate enum
+ template = templateGroup.getInstanceOf(ENUM_OBJECT_TEMPLATE);
+ List imports = new ArrayList();
+ imports.addAll(this.config.getDefaultModelImports());
+ enumName = this.getNameGenerator().getEnumName(operationParam.getName());
+ template.setAttribute("className", enumName);
+ template.setAttribute("description", operationParam.getDescription());
+ template.setAttribute("enumValueType", this.getDataTypeMappingProvider().getObjectType(operationParam.getDataType(), true));
+ for (String allowableValue : operationParam.getAllowableValues()) {
+ if(operationParam.getDataType().equalsIgnoreCase("string")){
+ valuePrefix = valueSuffix = "\"";
+ }
+ else{
+ valuePrefix = valueSuffix = "";
+ };
+ template.setAttribute("values.{name,value}",
+ this.getNameGenerator().applyClassNamingPolicy(allowableValue.replaceAll("-","_")),
+ this.getNameGenerator().applyMethodNamingPolicy(valuePrefix.concat(allowableValue).concat(valueSuffix)));
+ }
+ template.setAttribute(PACKAGE_NAME, config.getModelPackageName());
+ File aFile = new File(languageConfig.getModelClassLocation() + enumName + languageConfig.getClassFileExtension());
+ writeFile(aFile, template.toString(), "Enum class");
+ generatedEnums.add(operationParam.getName());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Generates one API class for each resource and each end point in the resource is translated as method.
+ * @param resources
+ * @param templateGroup
+ */
+ private void generateAPIClasses(List resources, StringTemplateGroup templateGroup) {
+
+ for(Resource resource : resources) {
+ List methods = new ArrayList();
+ List imports = new ArrayList();
+ imports.addAll(this.config.getDefaultServiceImports());
+ methods = resource.generateMethods(resource, dataTypeMappingProvider, nameGenerator);
+ StringTemplate template = templateGroup.getInstanceOf(API_OBJECT_TEMPLATE);
+ String className = resource.generateClassName(nameGenerator);
+ List filteredMethods = new ArrayList();
+ for(ResourceMethod method:methods){
+ if(!this.getCodeGenRulesProvider().isMethodIgnored(className, method.getName())){
+ filteredMethods.add(method);
+ }
+ }
+ template.setAttribute("imports", imports);
+ template.setAttribute(PACKAGE_NAME, config.getApiPackageName());
+ template.setAttribute("annotationPackageName", languageConfig.getAnnotationPackageName());
+ template.setAttribute("modelPackageName", config.getModelPackageName());
+ template.setAttribute("exceptionPackageName", languageConfig.getExceptionPackageName());
+ template.setAttribute("resource", className);
+ template.setAttribute("methods", filteredMethods);
+ template.setAttribute("extends", config.getServiceBaseClass(className));
+
+ File aFile = new File(languageConfig.getResourceClassLocation()+ resource.generateClassName(nameGenerator) +languageConfig.getClassFileExtension());
+ writeFile(aFile, template.toString(), "API CLasses");
+ }
+ }
+
+ /**
+ * Creates a wrapper model class that contains all model classes as list of objects.
+ * This class is used for storing test data
+ */
+ private void generateWrapperClassForTestData(List generatedClassNames, StringTemplateGroup templateGroup) {
+ Model model = new Model();
+ model.setName("TestData");
+ model.setDescription("Class used to store all the test data. This should not be used for any development");
+ List modelFields = new ArrayList();
+ model.setFields(modelFields);
+ for(String className : generatedClassNames){
+ ModelField aParam = new ModelField();
+ aParam.setName(this.getNameGenerator().applyMethodNamingPolicy(className)+"List");
+ aParam.setParamType(this.getDataTypeMappingProvider().getListReturnTypeSignature(className));
+ modelFields.add(aParam);
+ }
+
+ //add missing class from models
+ ModelField aParam = new ModelField();
+ aParam.setName("StringValueList");
+ aParam.setParamType(this.getDataTypeMappingProvider().getListReturnTypeSignature("StringValue"));
+ modelFields.add(aParam);
+
+ List imports = new ArrayList();
+ imports.addAll(this.config.getDefaultModelImports());
+ imports.addAll(this.getDataTypeMappingProvider().getListImportPackages());
+ for(ModelField param : model.getFields()){
+ for(String importDef : param.getFieldDefinition(this.getDataTypeMappingProvider()).getImportDefinitions()){
+ if(!imports.contains(importDef)){
+ imports.add(importDef);
+ }
+ }
+ }
+ StringTemplate template = templateGroup.getInstanceOf(MODEL_OBJECT_TEMPLATE);
+ template.setAttribute("fields", model.getFields());
+ template.setAttribute("imports", imports);
+ template.setAttribute("annotationPackageName", languageConfig.getAnnotationPackageName());
+ template.setAttribute("extends", config.getModelBaseClass());
+ template.setAttribute(PACKAGE_NAME, config.getModelPackageName());
+ template.setAttribute("className", model.getGenratedClassName());
+ File aFile = new File(languageConfig.getModelClassLocation()+model.getGenratedClassName()+languageConfig.getClassFileExtension());
+ writeFile(aFile, template.toString(), "Wrapper class for test data file");
+ }
+
+ private void writeFile(File aFile, String content, String classType){
+ try{
+ FileWriter aWriter = new FileWriter(aFile);
+ BufferedWriter bufWriter = new BufferedWriter(aWriter);
+ bufWriter.write(content);
+ bufWriter.close();
+ }catch(IOException ioe){
+ throw new CodeGenerationException("Error generating " + classType + " : " + ioe.getMessage());
+ }
+ }
+
+ public ApiConfiguration getConfig() {
+ return config;
+ }
+
+ public void setApiConfig(ApiConfiguration config) {
+ this.config = config;
+ }
+
+ public LanguageConfiguration getLanguageConfig() {
+ return languageConfig;
+ }
+
+ public void setLanguageConfig(LanguageConfiguration config) {
+ this.languageConfig = config;
+ }
+
+ public void setDataTypeMappingProvider(DataTypeMappingProvider dataTypeMappingProvider) {
+ this.dataTypeMappingProvider = dataTypeMappingProvider;
+ }
+
+ public void setCodeGenRulesProvider(RulesProvider codeGenRulesProvider) {
+ this.codeGenRulesProvider = codeGenRulesProvider;
+ }
+
+ public void setNameGenerator(NamingPolicyProvider nameGenerator) {
+ this.nameGenerator = nameGenerator;
+ }
+
+ public DataTypeMappingProvider getDataTypeMappingProvider() {
+ return dataTypeMappingProvider;
+ }
+
+ public RulesProvider getCodeGenRulesProvider() {
+ return codeGenRulesProvider;
+ }
+
+ public NamingPolicyProvider getNameGenerator() {
+ return nameGenerator;
+ }
+}
diff --git a/src/main/java/com/wordnik/swagger/codegen/FieldDefinition.java b/src/main/java/com/wordnik/swagger/codegen/FieldDefinition.java
new file mode 100644
index 00000000000..ea947f01200
--- /dev/null
+++ b/src/main/java/com/wordnik/swagger/codegen/FieldDefinition.java
@@ -0,0 +1,49 @@
+package com.wordnik.swagger.codegen;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FieldDefinition {
+
+ private String returnType;
+
+ private String name;
+
+ private String initialization;
+
+ private List importDefinitions = new ArrayList();
+
+ public String getReturnType() {
+ return returnType;
+ }
+
+ public void setReturnType(String returnType) {
+ this.returnType = returnType;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getInitialization() {
+ return initialization;
+ }
+
+ public void setInitialization(String initialization) {
+ this.initialization = initialization;
+ }
+
+ public List getImportDefinitions() {
+ return importDefinitions;
+ }
+
+ public String getNameForMethod() {
+ return name.substring(0,1).toUpperCase() + name.substring(1);
+ }
+
+
+}
diff --git a/src/main/java/com/wordnik/swagger/codegen/MethodArgument.java b/src/main/java/com/wordnik/swagger/codegen/MethodArgument.java
new file mode 100644
index 00000000000..86a8e3aa0d7
--- /dev/null
+++ b/src/main/java/com/wordnik/swagger/codegen/MethodArgument.java
@@ -0,0 +1,68 @@
+package com.wordnik.swagger.codegen;
+
+import com.wordnik.swagger.codegen.config.NamingPolicyProvider;
+
+public class MethodArgument {
+
+ public static String ARGUMENT_STRING = "String";
+ public static String ARGUMENT_INTEGER = "int";
+ public static String ARGUMENT_OBJECT = "Object";
+
+ private String name;
+
+ private String description;
+
+ private String dataType;
+
+ private String allowedValues;
+
+ private String inputModelClassArgument;
+ private String methodNameFromModelClass;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getDataType() {
+ return dataType;
+ }
+
+ public void setDataType(String dataType) {
+ this.dataType = dataType;
+ }
+
+ public String getAllowedValues() {
+ return allowedValues;
+ }
+
+ public void setAllowedValues(String allowedValues) {
+ this.allowedValues = allowedValues;
+ }
+
+ public String getInputModelClassArgument() {
+ return inputModelClassArgument;
+ }
+
+ public void setInputModelClassArgument(String inputModelClass, NamingPolicyProvider nameGenerator) {
+ this.inputModelClassArgument = nameGenerator.applyMethodNamingPolicy(inputModelClass);
+ if(name != null) {
+ methodNameFromModelClass = nameGenerator.createGetterMethodName(inputModelClassArgument, name);
+ }
+ }
+
+ public String getMethodNameFromModelClass() {
+ return methodNameFromModelClass;
+ }
+}
diff --git a/src/main/java/com/wordnik/swagger/codegen/ResourceMethod.java b/src/main/java/com/wordnik/swagger/codegen/ResourceMethod.java
new file mode 100644
index 00000000000..1feceabbb16
--- /dev/null
+++ b/src/main/java/com/wordnik/swagger/codegen/ResourceMethod.java
@@ -0,0 +1,177 @@
+package com.wordnik.swagger.codegen;
+
+import com.wordnik.swagger.codegen.resource.Model;
+
+import java.util.List;
+
+public class ResourceMethod {
+
+ private String description;
+
+ private List arguments;
+
+ private List queryParameters;
+
+ private List pathParameters;
+
+ private String returnValue;
+
+ private String returnClassName;
+
+ private String exceptionDescription;
+
+ private List argumentDefinitions;
+
+ private List argumentNames;
+
+ private String name;
+
+ private boolean authToken;
+
+ private String resourcePath;
+
+ private String methodType;
+
+ private boolean postObject;
+
+ private Model inputModel;
+
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public List getArguments() {
+ return arguments;
+ }
+
+ public void setArguments(List arguments) {
+ this.arguments = arguments;
+ }
+
+ public List getQueryParameters() {
+ return queryParameters;
+ }
+
+ public void setQueryParameters(List queryParameters) {
+ this.queryParameters = queryParameters;
+ }
+
+ public List getPathParameters() {
+ return pathParameters;
+ }
+
+ public void setPathParameters(List pathParameters) {
+ this.pathParameters = pathParameters;
+ }
+
+ public String getReturnValue() {
+ return returnValue;
+ }
+
+ public void setReturnValue(String returnValue) {
+ this.returnValue = returnValue;
+ }
+
+ public String getReturnClassName() {
+ return returnClassName;
+ }
+
+ public void setReturnClassName(String returnClassName) {
+ this.returnClassName = returnClassName;
+ }
+
+ public String getExceptionDescription() {
+ return exceptionDescription;
+ }
+
+ public void setExceptionDescription(String exceptionDescription) {
+ this.exceptionDescription = exceptionDescription;
+ }
+
+ public List getArgumentDefinitions() {
+ return argumentDefinitions;
+ }
+
+ public void setArgumentDefinitions(List argumentDefinitions) {
+ this.argumentDefinitions = argumentDefinitions;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isAuthToken() {
+ return authToken;
+ }
+
+ public void setAuthToken(boolean authToken) {
+ this.authToken = authToken;
+ }
+
+ public String getResourcePath() {
+ return resourcePath;
+ }
+
+ public void setResourcePath(String resourcePath) {
+ this.resourcePath = resourcePath;
+ }
+
+ public String getMethodType() {
+ return methodType;
+ }
+
+ public void setMethodType(String methodType) {
+ this.methodType = methodType;
+ }
+
+ public boolean isPostObject() {
+ return postObject;
+ }
+
+ public void setPostObject(boolean postObject) {
+ this.postObject = postObject;
+ }
+
+ public boolean isResponseVoid() {
+ return (this.getReturnClassName().equalsIgnoreCase("void"));
+ }
+
+ public Model getInputModel() {
+ return inputModel;
+ }
+
+ public void setInputModel(Model inputModel) {
+ this.inputModel = inputModel;
+ }
+
+ public List getArgumentNames() {
+ return argumentNames;
+ }
+
+ public void setArgumentNames(List argumentNames) {
+ this.argumentNames = argumentNames;
+ }
+
+ public boolean getHasArguments() {
+ if(this.getArgumentNames() != null && this.getArgumentNames().size() > 0){
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isReturnValueList() {
+ if(this.getReturnValue().startsWith("List")){
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/wordnik/swagger/codegen/api/SwaggerResourceDocReader.java b/src/main/java/com/wordnik/swagger/codegen/api/SwaggerResourceDocReader.java
new file mode 100644
index 00000000000..776cac05780
--- /dev/null
+++ b/src/main/java/com/wordnik/swagger/codegen/api/SwaggerResourceDocReader.java
@@ -0,0 +1,156 @@
+package com.wordnik.swagger.codegen.api;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import com.wordnik.swagger.codegen.config.DataTypeMappingProvider;
+import com.wordnik.swagger.codegen.resource.Endpoint;
+import com.wordnik.swagger.codegen.resource.Resource;
+import com.wordnik.swagger.codegen.config.ApiConfiguration;
+import com.wordnik.swagger.codegen.config.NamingPolicyProvider;
+import com.wordnik.swagger.exception.CodeGenerationException;
+import org.codehaus.jackson.map.DeserializationConfig;
+import org.codehaus.jackson.map.ObjectMapper;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * User: deepakmichael
+ * Date: 27/07/11
+ * Time: 9:32 PM
+ */
+public class SwaggerResourceDocReader {
+
+ private static String HEADER_NAME_API_VERSION = "Wordnik-Api-Version";
+
+ private String baseUrl;
+ private String apiKey;
+ private String apiListResource;
+ private ApiConfiguration apiConfiguration;
+ private final DataTypeMappingProvider dataTypeMappingProvider;
+ private final NamingPolicyProvider nameGenerator;
+
+ public SwaggerResourceDocReader(ApiConfiguration apiConfiguration, DataTypeMappingProvider dataTypeMappingProvider, NamingPolicyProvider nameGenerator) {
+ this.apiConfiguration = apiConfiguration;
+ this.dataTypeMappingProvider = dataTypeMappingProvider;
+ this.nameGenerator = nameGenerator;
+ readApiConfig();
+
+ }
+
+ public void readApiConfig() {
+ baseUrl = apiConfiguration.getApiUrl();
+ apiKey = apiConfiguration.getApiKey();
+ apiListResource = apiConfiguration.getApiListResource();
+ }
+
+ /**
+ * Reads the documentation of the resources and constructs the resource object that can be used
+ * for generating the driver related classes. The resource list string should be "," separated
+ */
+ public List readResourceDocumentation() {
+
+ List resourceDocs = new ArrayList();
+ Client apiClient = Client.create();
+
+ String resourceList = retrieveResourceList(apiClient);
+
+ //valid for input
+ if (baseUrl == null || resourceList == null ||
+ baseUrl.trim().length() == 0 ||
+ resourceList.trim().length() == 0) {
+ throw new CodeGenerationException("Base URL or Resource list input is null");
+ }
+
+
+ //create list of resource URL
+ String[] resources = resourceList.split(",");
+ List resourceURLs = new ArrayList();
+ for (String resource : resources) {
+ resource = trimResourceName(resource);
+ if (!resource.equals(trimResourceName( apiListResource ))) {
+ if(!resource.endsWith(".json")){
+ resource = resource.concat(".json");
+ }
+ resourceURLs.add(baseUrl + resource);
+ }
+ }
+
+ //make connection to resource and get the documentation
+ for (String resourceURL : resourceURLs) {
+ WebResource aResource = apiClient.resource(resourceURL);
+ aResource.header("api_key", apiKey);
+ ClientResponse clientResponse = aResource.header("api_key", apiKey).get(ClientResponse.class);
+ String version = clientResponse.getHeaders().get(HEADER_NAME_API_VERSION).get(0);//TODO - check if this is required
+ String response = clientResponse.getEntity(String.class);
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.getDeserializationConfig().set(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ Resource aResourceDoc = deserializeResource(response, mapper);
+ aResourceDoc.setApiVersion(version);
+ resourceDocs.add(aResourceDoc);
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ throw new CodeGenerationException("Error in coverting resource json documentation to java object");
+ }
+ }
+ return resourceDocs;
+
+ }
+
+ private String trimResourceName(String resource) {
+ if(resource.startsWith("/")){
+ resource = resource.substring(1,resource.length());
+ }
+ return resource;
+ }
+
+ private String retrieveResourceList(Client apiClient) {
+ String resourceCsv = "";
+ Resource resourceApi;
+ String apiResourceUrl = null;
+ if(apiListResource == null){
+ throw new CodeGenerationException("apiListingUrl needs to be defined in api configuration object");
+ }
+ if(!apiListResource.endsWith(".json")){
+ apiResourceUrl = trimResourceName( apiListResource.concat(".json") );
+ }
+
+ apiResourceUrl = baseUrl.concat(apiResourceUrl);
+
+ WebResource aResource = apiClient.resource(apiResourceUrl);
+ aResource.header("api_key", apiKey);
+ ClientResponse clientResponse = aResource.header("api_key", apiKey).get(ClientResponse.class);
+ String response = clientResponse.getEntity(String.class);
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.getDeserializationConfig().set(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ resourceApi = deserializeResource(response, mapper);
+
+ for(Endpoint api: resourceApi.getEndPoints()){
+ resourceCsv += (api.getPath() + ",");
+ }
+ }
+ catch (IOException ex) {
+ throw new CodeGenerationException("Error in coverting resource listing json documentation to java object");
+
+ }
+ return resourceCsv;
+ }
+
+ /**
+ * Deserializes the response and returns a Response object
+ * @param response
+ * @param mapper
+ * @return
+ * @throws IOException
+ */
+ private Resource deserializeResource(String response, ObjectMapper mapper) throws IOException {
+ Resource resource = mapper.readValue(response, Resource.class);
+ resource.generateModelsFromWrapper(nameGenerator);
+ return resource;
+ }
+
+}
diff --git a/src/main/java/com/wordnik/swagger/codegen/config/ApiConfiguration.java b/src/main/java/com/wordnik/swagger/codegen/config/ApiConfiguration.java
new file mode 100644
index 00000000000..276f05fbaac
--- /dev/null
+++ b/src/main/java/com/wordnik/swagger/codegen/config/ApiConfiguration.java
@@ -0,0 +1,131 @@
+package com.wordnik.swagger.codegen.config;
+
+import com.wordnik.swagger.exception.CodeGenerationException;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * User: ramesh
+ * Date: 5/31/11
+ * Time: 7:04 AM
+ */
+public class ApiConfiguration {
+
+ private Map baseClassNames = new HashMap();
+
+ private String defaultServiceBaseClass = "Object";
+
+ private String modelBaseClass = "Object";
+ /**
+ * Default model imports that we need to include in all service classes. This is needed because some times,
+ * we may need to write custom classes and those classes will not be known to code generation. To import those
+ * classes in service classes we use this property
+ */
+ private List defaultModelImports;
+ /**
+ * Default service imports that we need to include in all service classes. This is needed because some times,
+ * we may need to write custom classes ans those classes will not be known to code generation. To import those
+ * classes in service classes we use this property
+ */
+ private List defaultServiceImports;
+ private String modelPackageName;
+ private String apiPackageName;
+
+ private String apiUrl;
+ private String apiKey;
+ private String apiListResource;
+
+ public ApiConfiguration() {
+
+ }
+
+ public void setServiceBaseClass(String defaultServiceBaseClass) {
+ this.defaultServiceBaseClass = defaultServiceBaseClass;
+ }
+
+ public void setServiceBaseClass(String serviceName, String className) {
+ if(serviceName == null || serviceName.length() == 0){
+ throw new CodeGenerationException("Error setting base class for service: service name was not provided");
+ }
+
+ if(className == null || className.length() == 0) {
+ throw new CodeGenerationException("Error settting base class for service: class name was not provided");
+ }
+
+ baseClassNames.put(serviceName, className);
+ }
+
+ public String getServiceBaseClass(String serviceName) {
+ if(baseClassNames.containsKey(serviceName)){
+ return baseClassNames.get(serviceName);
+ }
+ return defaultServiceBaseClass;
+ }
+
+ public String getModelBaseClass() {
+ return modelBaseClass;
+ }
+
+ public void setModelBaseClass(String modelBaseClass) {
+ this.modelBaseClass = modelBaseClass;
+ }
+
+
+ public List getDefaultModelImports() {
+ return defaultModelImports;
+ }
+
+ public void setDefaultModelImports(List defaultModelImports) {
+ this.defaultModelImports = defaultModelImports;
+ }
+
+ public List getDefaultServiceImports() {
+ return defaultServiceImports;
+ }
+
+ public void setDefaultServiceImports(List defaultServiceImports) {
+ this.defaultServiceImports = defaultServiceImports;
+ }
+
+ public String getModelPackageName() {
+ return modelPackageName;
+ }
+
+ public void setModelPackageName(String modelPackageName) {
+ this.modelPackageName = modelPackageName;
+ }
+
+ public String getApiPackageName() {
+ return apiPackageName;
+ }
+
+ public void setApiPackageName(String apiPackageName) {
+ this.apiPackageName = apiPackageName;
+ }
+
+ public String getApiUrl() {
+ return apiUrl;
+ }
+
+ public void setApiUrl(String apiUrl) {
+ this.apiUrl = apiUrl;
+ }
+
+ public String getApiKey() {
+ return apiKey;
+ }
+
+ public void setApiKey(String apiKey) {
+ this.apiKey = apiKey;
+ }
+
+ public String getApiListResource() {
+ return apiListResource;
+ }
+
+ public void setApiListResource(String apiListResource) {
+ this.apiListResource = apiListResource;
+ }
+}
diff --git a/src/main/java/com/wordnik/swagger/codegen/config/DataTypeMappingProvider.java b/src/main/java/com/wordnik/swagger/codegen/config/DataTypeMappingProvider.java
new file mode 100644
index 00000000000..ab88b8a1a95
--- /dev/null
+++ b/src/main/java/com/wordnik/swagger/codegen/config/DataTypeMappingProvider.java
@@ -0,0 +1,187 @@
+package com.wordnik.swagger.codegen.config;
+
+import java.util.List;
+
+/**
+ * Implementations of this class is responsible for generating mapping between rest data types and language
+ * specific data type
+ *
+ * User: ramesh
+ * Date: 5/27/11
+ * Time: 7:39 AM
+ */
+public interface DataTypeMappingProvider {
+
+ /**
+ * Checks nature of data type.
+ *
+ * This is needed in generating return values, input and model class generations.
+ *
+ * Example: in java String
, Integer
, Boolean
are considered as primitive
+ * types
+ * @param type
+ * @return
+ */
+ public boolean isPrimitiveType(String type);
+
+ /**
+ * provide the sttring that needs to be used when defining methods that returns no values
+ *
+ * Example: in java this value will be void
+ * @return
+ */
+ public String getReturnTypeForVoidMethods();
+
+ /**
+ * Signature that should be used when returning list of given object type.
+ *
+ * Example: in java this output will look as List
for methods that returns a list of user objects
+ * @param typeClass of class that list object contains.
+ * @return
+ */
+ public String getListReturnTypeSignature(String typeClass);
+
+ /**
+ * Signature that should be used when returning map of given object type.
+ *
+ * Example: in java this output will look as Map
for methods that returns maps
+ * @param typeClass of class that list object contains.
+ * @return
+ */
+ public String getMapReturnTypeSignature(String typeClass);
+
+ /**
+ * Signature that should be used when returning set of given object type.
+ *
+ * Example: in java this output will look as Set
for methods that returns a set of user objects
+ * @param typeClass of class that the set object contains.
+ * @return
+ */
+ public String getSetReturnTypeSignature(String typeClass);
+
+ /**
+ * Initialization need for list objects. Example. If it is java list the initialization will look as
+ *
+ *
+ * new ArrayList()
+ *
+ *
+ * @param typeClass
+ * @return
+ */
+ public String generateListInitialization(String typeClass);
+
+ /**
+ * Initialization need for map objects. Example. If it is java map the initialization will look as
+ *
+ *
+ * new HashMap()
+ *
+ *
+ * @param typeClass
+ * @return
+ */
+ public String generateMapInitialization(String typeClass);
+
+ /**
+ * Initialization need for set objects. Example. If it is java set the initialization will look as
+ *
+ *
+ * new HashSet()
+ *
+ *
+ * @param typeClass
+ * @return
+ */
+ public String generateSetInitialization(String typeClass);
+
+ /**
+ * Gets list of imports that needs to be included when used objects of type List.
+ *
+ * Example: in java while using lists we use an interface of List
and implementation of
+ * ArrayList
. SO the output will as follows:
+ *
+ * List imports = new ArrayList();
+ imports.add("java.util.List");
+ imports.add("java.util.ArrayList");
+ *
+ * @return
+ */
+ public List getListImportPackages();
+
+ /**
+ * Gets list of imports that needs to be included when used objects of type Map.
+ *
+ * Example: in java while using maps we use an interface of Map
and implementation of
+ * HashMap
. SO the output will as follows:
+ *
+ * List imports = new ArrayList();
+ imports.add("java.util.Map");
+ imports.add("java.util.HashMap");
+ *
+ * @return
+ */
+ public List getMapImportPackages();
+
+ /**
+ * Gets list of imports that needs to be included when used objects of type Set.
+ *
+ * Example: in java while using sets we use an interface of Set
and implementation of
+ * HashSet
. SO the output will as follows:
+ *
+ * List imports = new ArrayList();
+ imports.add("java.util.Set");
+ imports.add("java.util.HashSet");
+ *
+ * @return
+ */
+ public List getSetImportPackages();
+
+ /**
+ * Gets list of imports that needs to be included when used objects of type Date.
+ *
+ * Example: in java while using Data we use . So the output will as follows:
+ *
+ * List imports = new ArrayList();
+ imports.add("java.util.Date");
+ *
+ * @return
+ */
+ public List getDateImports();
+
+ /**
+ * Object type definition for a given input
+ *
+ * @param type
+ * @param primitiveObject
+ * @return
+ */
+ public String getObjectType(String type, boolean primitiveObject);
+
+ /**
+ * Gets the value of return type converted from web service response documentation.
+ *
+ * Example: If the resource documentation ays return type as List[User] the equivalent translation for java will be
+ *
+ * List
+ *
+ * If the input is Map[int, String] the equivalent java translation will be Map
+ * @param type
+ * @return
+ */
+ public String getReturnValueType(String type);
+
+ /**
+ * Gets the class of return values from web service response documentation. If the service returns list the class
+ * indicates type of object in the list
+ *
+ * Example: If the resource documentation ays return type as List[User] the equivalent translation for java will be
+ *
+ * User
+ *
+ * If the input is Map[int] the equivalent java translation will be Int
+ * @param type
+ * @return
+ */
+ public String getReturnClassType(String type);
+}
diff --git a/src/main/java/com/wordnik/swagger/codegen/config/LanguageConfiguration.java b/src/main/java/com/wordnik/swagger/codegen/config/LanguageConfiguration.java
new file mode 100644
index 00000000000..1632453315d
--- /dev/null
+++ b/src/main/java/com/wordnik/swagger/codegen/config/LanguageConfiguration.java
@@ -0,0 +1,78 @@
+package com.wordnik.swagger.codegen.config;
+
+import com.wordnik.swagger.exception.CodeGenerationException;
+
+/**
+ * User: deepakmichael
+ * Date: 23/07/11
+ * Time: 8:01 AM
+ */
+public class LanguageConfiguration {
+
+ private String classFileExtension;
+
+ private String templateLocation;
+
+ private String modelClassLocation;
+
+ private String resourceClassLocation;
+
+ private String exceptionPackageName;
+
+ private String annotationPackageName;
+
+ public String getClassFileExtension() {
+ return classFileExtension;
+ }
+
+ public void setClassFileExtension(String classFileExtension) {
+ this.classFileExtension = classFileExtension;
+ }
+
+ public String getTemplateLocation() {
+ return templateLocation;
+ }
+
+ public void setTemplateLocation(String templateLocation) {
+ this.templateLocation = templateLocation;
+ }
+
+ public void setOutputDirectory(String outputDirectory) {
+
+ if(outputDirectory == null || outputDirectory.length() == 0){
+ throw new CodeGenerationException("Error creating output path : Output path was null ");
+ }
+ outputDirectory = outputDirectory.endsWith("/") ? outputDirectory.substring(0, outputDirectory.lastIndexOf("/")) : outputDirectory;
+
+
+ this.modelClassLocation = outputDirectory + "/model/";
+ this.resourceClassLocation = outputDirectory + "/api/";
+ }
+
+ public String getModelClassLocation() {
+ return modelClassLocation;
+ }
+
+ public String getResourceClassLocation() {
+ return resourceClassLocation;
+ }
+
+ public String getExceptionPackageName() {
+ return exceptionPackageName;
+ }
+
+ public void setExceptionPackageName(String exceptionPackageName) {
+ this.exceptionPackageName = exceptionPackageName;
+ }
+
+ public String getAnnotationPackageName() {
+ return annotationPackageName;
+ }
+
+ public void setAnnotationPackageName(String annotationPackageName) {
+ this.annotationPackageName = annotationPackageName;
+ }
+
+
+
+}
diff --git a/src/main/java/com/wordnik/swagger/codegen/config/NamingPolicyProvider.java b/src/main/java/com/wordnik/swagger/codegen/config/NamingPolicyProvider.java
new file mode 100644
index 00000000000..590f57d2683
--- /dev/null
+++ b/src/main/java/com/wordnik/swagger/codegen/config/NamingPolicyProvider.java
@@ -0,0 +1,105 @@
+package com.wordnik.swagger.codegen.config;
+
+/**
+ * Implementor of this class is responsible for generating the names for service classes and methods in
+ * each of those service classes
+ *
+ * User: ramesh
+ * Date: 5/27/11
+ * Time: 7:36 AM
+ */
+public interface NamingPolicyProvider {
+
+ /**
+ * Gets name of the version checker class. We need not provide extension for the class as that will be read
+ * through a class extention configuration value.
+ *
+ * Example: In java this is VersionChecker.
+ *
+ * @return
+ */
+ public String getVersionCheckerClassName();
+
+
+ /**
+ * Convert input string into class name format.
+ *
+ * Example: in java this will be init caps.
+ *
+ * @param input
+ * @return
+ */
+ public String applyClassNamingPolicy(String input);
+
+ /**
+ * Transform the input string into method naming convention format.
+ *
+ * Example: In java, the will be Camel case
+ *
+ * @param input
+ * @return
+ */
+ public String applyMethodNamingPolicy(String input);
+
+ /**
+ * Generates the name of service based on resource path.
+ *
+ * Example: for a resource path of http://beta.wordnik.com/v4/word.json the service name can be WordAPI
+ *
+ * @param resourcePath
+ * @return
+ */
+ public String getServiceName(String resourcePath);
+
+
+ /**
+ * Generates the name of service methods.
+ *
+ * Resource documentation provides suggested names. Individual language can choose to use suggested name or
+ * generate the name based on end point path. Example: IN java we use suggested name
+ *
+ * @param endPoint
+ * @param suggestedName
+ * @return
+ */
+ public String getMethodName(String endPoint, String suggestedName);
+
+
+ /**
+ * Generate of the input object using the resource path name.
+ *
+ * When the number of arguments for a method increases beyond certain limit, we want to capture all the arguments
+ * as a single input objects so that it is easy for client to understand the API.
+ *
+ * Example: get examples API on words resource takes inputs as : word, limit, include duplicates, content provider,
+ * use canonical, skip, limit. Instead of having all these as individual arguments create an input object with name
+ * WordsExampleInput and have above arguments as properties fo the object.
+ *
+ * @param serviceName
+ * @param resourcePath
+ * @return
+ */
+ public String getInputObjectName(String serviceName, String resourcePath);
+
+ /**
+ * Generates a name for an enum for the param or field name.
+ *
+ * Example: for a param source the return could be SourceEnum
+ *
+ * @param input
+ * @return
+ */
+ public String getEnumName(String input);
+
+ /**
+ * 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);
+}
diff --git a/src/main/java/com/wordnik/swagger/codegen/config/RulesProvider.java b/src/main/java/com/wordnik/swagger/codegen/config/RulesProvider.java
new file mode 100644
index 00000000000..48f9756fc4f
--- /dev/null
+++ b/src/main/java/com/wordnik/swagger/codegen/config/RulesProvider.java
@@ -0,0 +1,23 @@
+package com.wordnik.swagger.codegen.config;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Maintains the overriding rules that we should use while generating the code.
+ *
+ * Example; If we need to ignore any REST methods or if we need special service extention classes they can be
+ * supplied through this configuration
+ *
+ * User: ramesh
+ * Date: 4/26/11
+ * Time: 8:01 AM
+ */
+public interface RulesProvider {
+
+ public boolean isMethodIgnored(String serviceName, String methodName);
+
+ public boolean isModelIgnored(String modelName);
+}
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
new file mode 100644
index 00000000000..e182d836808
--- /dev/null
+++ b/src/main/java/com/wordnik/swagger/codegen/config/common/CamelCaseNamingPolicyProvider.java
@@ -0,0 +1,133 @@
+package com.wordnik.swagger.codegen.config.common;
+
+import com.wordnik.swagger.codegen.resource.Model;
+import com.wordnik.swagger.codegen.config.NamingPolicyProvider;
+import com.wordnik.swagger.exception.CodeGenerationException;
+
+/**
+ * User: ramesh
+ * Date: 5/31/11
+ * Time: 7:03 AM
+ */
+public class CamelCaseNamingPolicyProvider implements NamingPolicyProvider {
+
+ /**
+ * gets the name of class that is responsible for tracking current library version
+ * @return
+ */
+ public String getVersionCheckerClassName() {
+ return "VersionChecker";
+ }
+
+ /**
+ * Converts the first character of the input into string.
+ * Example: If the input is word, the return value will be Word
+ * @param input
+ * @return
+ */
+ public String applyClassNamingPolicy(String input) {
+ if(input != null && input.length() > 0) {
+ return input.substring(0,1).toUpperCase() + input.substring(1);
+ }else{
+ throw new CodeGenerationException("Error converting input to first letter caps becuase of null input");
+ }
+ }
+
+ /**
+ * Converts the first character of the input into string.
+ * Example: If the input is word, the return value will be Word
+ * @param input
+ * @return
+ */
+ public String applyMethodNamingPolicy(String input) {
+ if(input != null && input.length() > 0) {
+ return input.substring(0,1).toLowerCase() + input.substring(1);
+ }else{
+ throw new CodeGenerationException("Error converting input to first letter to lower because of null input");
+ }
+ }
+
+ public String getServiceName(String resourcePath) {
+ String className = null;
+ int index = resourcePath.indexOf(".");
+ if(index >= 0) {
+ String resourceName = resourcePath.substring(1,index);
+ className = applyClassNamingPolicy(resourceName);
+ }else{
+ String[] paths = resourcePath.split("/");
+ for(String path : paths) {
+ if(path != null && path.length() > 0) {
+ className = applyClassNamingPolicy(path);
+ break;
+ }
+ }
+ }
+ return className+ "API";
+ }
+
+ /**
+ * Generates the name of service methods.
+ *
+ * Resource documentation provides suggested names. Individual language can choose to use suggested name or
+ * generate the name based on end point path. Example: IN java we use suggested name
+ *
+ * @param endPoint
+ * @param suggestedName
+ * @return
+ */
+ public String getMethodName(String endPoint, String suggestedName) {
+ return suggestedName;
+ }
+
+
+ public String getInputObjectName(String serviceName, String resourcePath) {
+
+ String inputobjectName = serviceName.substring(0, serviceName.length() - 3);
+
+ String[] pathElements = resourcePath.split("/");
+ StringBuilder urlPath = new StringBuilder("");
+ if(pathElements != null){
+ for(int i=0; i < pathElements.length; i++){
+ String pathElement = pathElements[i];
+ if(pathElement != null && pathElement.length() > 0) {
+ int position = pathElement.indexOf("{");
+ if(position < 0) {
+ inputobjectName = inputobjectName + applyClassNamingPolicy(pathElement) + Model.INPUT_OBJECT_SUFFIX;
+ }
+ }
+ }
+ }
+ return inputobjectName;
+ }
+
+ /**
+ * Generates a name for an enum for the param or field name.
+ *
+ * Example: for a param source the return could be SourceEnum
+ *
+ * @param input
+ * @return
+ */
+ public String getEnumName(String input) {
+ if (input != null && input.length() > 0) {
+ return this.applyClassNamingPolicy(input).concat("Values");
+ } else {
+ throw new CodeGenerationException("Error getting Enum name becuase of null input");
+ }
+ }
+
+ /**
+ * 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+".get"+ applyClassNamingPolicy(attributeName)+"()";
+ }
+
+}
diff --git a/src/main/java/com/wordnik/swagger/codegen/config/java/JavaCodeGenRulesProvider.java b/src/main/java/com/wordnik/swagger/codegen/config/java/JavaCodeGenRulesProvider.java
new file mode 100644
index 00000000000..a70681bb5f8
--- /dev/null
+++ b/src/main/java/com/wordnik/swagger/codegen/config/java/JavaCodeGenRulesProvider.java
@@ -0,0 +1,33 @@
+package com.wordnik.swagger.codegen.config.java;
+
+import com.wordnik.swagger.codegen.config.RulesProvider;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * User: ramesh
+ * Date: 5/31/11
+ * Time: 7:04 AM
+ */
+public class JavaCodeGenRulesProvider implements RulesProvider {
+
+ private List ignoreMethods = new ArrayList();
+ private List ignoreModels = new ArrayList();
+
+ public JavaCodeGenRulesProvider() {
+ ignoreMethods.add("WordAPI.getWordFrequency");
+ ignoreMethods.add("WordAPI.getAudio");
+ ignoreMethods.add("WordAPI.getWordStats");
+ ignoreModels.add("wordStats");
+ }
+
+ public boolean isMethodIgnored(String serviceName, String methodName){
+ return (ignoreMethods.contains(serviceName+"."+methodName));
+ }
+
+ public boolean isModelIgnored(String modelName) {
+ return ignoreModels.contains(modelName);
+ }
+
+}
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
new file mode 100644
index 00000000000..769a8a01200
--- /dev/null
+++ b/src/main/java/com/wordnik/swagger/codegen/config/java/JavaDataTypeMappingProvider.java
@@ -0,0 +1,190 @@
+package com.wordnik.swagger.codegen.config.java;
+
+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 JavaDataTypeMappingProvider implements DataTypeMappingProvider {
+
+ public static Map primitiveValueMap = new HashMap();
+ static{
+ primitiveValueMap.put("string", "String");
+ primitiveValueMap.put("String", "String");
+ primitiveValueMap.put("int", "int");
+ primitiveValueMap.put("integer", "int");
+ primitiveValueMap.put("Integer", "int");
+ primitiveValueMap.put("boolean", "boolean");
+ primitiveValueMap.put("Boolean", "boolean");
+ primitiveValueMap.put("long", "long");
+ primitiveValueMap.put("Long", "long");
+ primitiveValueMap.put("float", "float");
+ primitiveValueMap.put("Float", "float");
+ 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", "Integer");
+ primitiveObjectMap.put("integer", "Integer");
+ primitiveObjectMap.put("Integer", "Integer");
+ primitiveObjectMap.put("boolean", "Boolean");
+ primitiveObjectMap.put("Boolean", "Boolean");
+ primitiveObjectMap.put("long", "Long");
+ primitiveObjectMap.put("Long", "Long");
+ primitiveObjectMap.put("float", "Float");
+ primitiveObjectMap.put("Float", "Float");
+ 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("boolean") || type.equalsIgnoreCase("float")|| type.equalsIgnoreCase("long") ){
+ 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 "List<"+nameGenerator.applyClassNamingPolicy(typeClass)+">";
+ }
+
+ public String getReturnTypeForVoidMethods() {
+ return "void";
+ }
+
+ public String getMapReturnTypeSignature(String typeClass) {
+ return "Map<"+nameGenerator.applyClassNamingPolicy(typeClass)+">";
+ }
+
+ public String getSetReturnTypeSignature(String typeClass) {
+ return "Set<"+nameGenerator.applyClassNamingPolicy(typeClass)+">";
+ }
+
+ public String generateListInitialization(String typeClass) {
+ return " new ArrayList<"+nameGenerator.applyClassNamingPolicy(typeClass)+">()";
+ }
+
+ public String generateMapInitialization(String typeClass) {
+ return " new HashMap<"+nameGenerator.applyClassNamingPolicy(typeClass)+">()";
+ }
+
+ public String generateSetInitialization(String typeClass) {
+ return " new HashSet<"+nameGenerator.applyClassNamingPolicy(typeClass)+">()";
+ }
+
+ public List getListImportPackages() {
+ List imports = new ArrayList();
+ imports.add("java.util.List");
+ imports.add("java.util.ArrayList");
+ return imports;
+ }
+
+ public List getMapImportPackages() {
+ List imports = new ArrayList();
+ imports.add("java.util.Map");
+ imports.add("java.util.HashMap");
+ return imports;
+ }
+
+ public List getSetImportPackages() {
+ List imports = new ArrayList();
+ imports.add("java.util.Set");
+ imports.add("java.util.HashSet");
+ return imports; }
+
+
+ public List getDateImports() {
+ List imports = new ArrayList();
+ imports.add("java.util.Date");
+ 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 getReturnClassType(String type) {
+ 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;
+ }
+
+ /**
+ * 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 getReturnValueType(String type) {
+ if(type.equalsIgnoreCase("void")|| type.equalsIgnoreCase("ok")){
+ return "void";
+ }
+ String classShortName = "";
+ if(type.startsWith("List[")){
+ classShortName = type.substring(5, type.length()-1);
+ classShortName = "List<"+getObjectType(classShortName, true)+">";
+ }else if (type.startsWith("Map[")) {
+ classShortName = type.substring(4, type.length()-1);
+ classShortName = "Map<"+getObjectType(classShortName, true) +">";
+ }else if (type.startsWith("Set[")) {
+ classShortName = type.substring(4, type.length()-1);
+ classShortName = "Set<"+getObjectType(classShortName, true) +">";
+ }else{
+ classShortName = getObjectType(type, true);
+ }
+ return classShortName;
+ }
+}
diff --git a/src/main/java/com/wordnik/swagger/codegen/config/java/JavaLibCodeGen.java b/src/main/java/com/wordnik/swagger/codegen/config/java/JavaLibCodeGen.java
new file mode 100644
index 00000000000..39f0717d1c3
--- /dev/null
+++ b/src/main/java/com/wordnik/swagger/codegen/config/java/JavaLibCodeGen.java
@@ -0,0 +1,80 @@
+package com.wordnik.swagger.codegen.config.java;
+
+import com.wordnik.swagger.codegen.DriverCodeGenerator;
+import com.wordnik.swagger.codegen.config.ApiConfiguration;
+import com.wordnik.swagger.codegen.config.LanguageConfiguration;
+import com.wordnik.swagger.codegen.config.common.CamelCaseNamingPolicyProvider;
+import com.wordnik.swagger.exception.CodeGenerationException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * User: ramesh
+ * Date: 6/16/11
+ * Time: 1:31 PM
+ */
+public class JavaLibCodeGen extends DriverCodeGenerator {
+
+ 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 output path");
+ }
+
+ String outputPath = args[0];
+ JavaLibCodeGen codeGenerator = new JavaLibCodeGen(outputPath);
+ codeGenerator.generateCode();
+ }
+
+ public JavaLibCodeGen(String outputPath){
+
+ this.setApiConfig(initializeApiConfig());
+ this.setLanguageConfig(initializeLangConfig(outputPath));
+
+ this.setDataTypeMappingProvider(new JavaDataTypeMappingProvider());
+ this.setCodeGenRulesProvider(new JavaCodeGenRulesProvider());
+ this.setNameGenerator(new CamelCaseNamingPolicyProvider());
+ }
+
+ private ApiConfiguration initializeApiConfig() {
+ ApiConfiguration apiConfiguration = new ApiConfiguration();
+ apiConfiguration.setServiceBaseClass("WordAPI","AbstractWordAPI");
+ //default base class for services if not specified for a service
+ apiConfiguration.setServiceBaseClass("WordnikAPI");
+ apiConfiguration.setModelBaseClass("WordnikObject");
+
+ List defaultModelImports = new ArrayList();
+ defaultModelImports.add("com.wordnik.swagger.common.WordListType");
+ defaultModelImports.add("com.wordnik.swagger.common.StringValue");
+ defaultModelImports.add("com.wordnik.swagger.common.Size");
+ defaultModelImports.add("com.wordnik.swagger.common.WordnikObject");
+
+ List defaultServiceImports = new ArrayList();
+ defaultServiceImports.add("com.wordnik.swagger.model.Long");
+ defaultServiceImports.add("com.wordnik.swagger.common.*");
+ defaultServiceImports.add("com.wordnik.swagger.common.ext.*");
+
+ apiConfiguration.setDefaultModelImports(defaultModelImports);
+ apiConfiguration.setDefaultServiceImports(defaultServiceImports);
+
+ apiConfiguration.setModelPackageName("com.wordnik.swagger.model");
+ apiConfiguration.setApiPackageName("com.wordnik.swagger.api");
+
+ apiConfiguration.setApiKey("myKey");
+ apiConfiguration.setApiUrl("http://swagr.api.wordnik.com/v4/");
+ apiConfiguration.setApiListResource("/list");
+
+ return apiConfiguration;
+ }
+
+ private LanguageConfiguration initializeLangConfig(String outputPath) {
+ LanguageConfiguration javaConfiguration = new LanguageConfiguration();
+ javaConfiguration.setClassFileExtension(".java");
+ javaConfiguration.setOutputDirectory(outputPath);
+ javaConfiguration.setTemplateLocation("conf/java/templates");
+ javaConfiguration.setExceptionPackageName("com.wordnik.swagger.exception");
+ javaConfiguration.setAnnotationPackageName("com.wordnik.swagger.annotations");
+ return javaConfiguration;
+ }
+
+}
diff --git a/src/main/java/com/wordnik/swagger/codegen/resource/ApiModelDefn.java b/src/main/java/com/wordnik/swagger/codegen/resource/ApiModelDefn.java
new file mode 100644
index 00000000000..ff8e2a53881
--- /dev/null
+++ b/src/main/java/com/wordnik/swagger/codegen/resource/ApiModelDefn.java
@@ -0,0 +1,53 @@
+package com.wordnik.swagger.codegen.resource;
+
+import com.wordnik.swagger.codegen.config.NamingPolicyProvider;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * User: deepakmichael
+ * Date: 19/07/11
+ * Time: 1:21 AM
+ */
+public class ApiModelDefn {
+
+ @JsonProperty("id")
+ private String id;
+ @JsonProperty("properties")
+ private ApiPropertyListWrapper properties;
+ @JsonProperty("description")
+ private String description;
+
+ @JsonProperty("id")
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ @JsonProperty("properties")
+ public ApiPropertyListWrapper getProperties() {
+ return properties;
+ }
+
+ public void setProperties(ApiPropertyListWrapper properties) {
+ this.properties = properties;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public Model toModel(String modelName, NamingPolicyProvider nameGenerator) {
+ Model model = new Model();
+ model.setName(modelName);
+ model.setDescription(this.getDescription());
+ model.setFields( this.getProperties().toFieldList( nameGenerator ) );
+ return model;
+ }
+}
diff --git a/src/main/java/com/wordnik/swagger/codegen/resource/ApiModelListWrapper.java b/src/main/java/com/wordnik/swagger/codegen/resource/ApiModelListWrapper.java
new file mode 100644
index 00000000000..82e2e334ccd
--- /dev/null
+++ b/src/main/java/com/wordnik/swagger/codegen/resource/ApiModelListWrapper.java
@@ -0,0 +1,27 @@
+package com.wordnik.swagger.codegen.resource;
+
+import org.codehaus.jackson.annotate.JsonAnyGetter;
+import org.codehaus.jackson.annotate.JsonAnySetter;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+public class ApiModelListWrapper implements Serializable
+{
+
+ private Map modelList = new HashMap();
+
+ @JsonAnyGetter
+ public Map getModelList() {
+ return this.modelList;
+ }
+
+ @JsonAnySetter
+ public void setModelList(String modelName, ApiModelDefn modelDefn) {
+ this.modelList.put(modelName, modelDefn);
+ }
+
+}
diff --git a/src/main/java/com/wordnik/swagger/codegen/resource/ApiPropertyDefn.java b/src/main/java/com/wordnik/swagger/codegen/resource/ApiPropertyDefn.java
new file mode 100644
index 00000000000..4ecb60a0f03
--- /dev/null
+++ b/src/main/java/com/wordnik/swagger/codegen/resource/ApiPropertyDefn.java
@@ -0,0 +1,176 @@
+package com.wordnik.swagger.codegen.resource;
+
+import org.codehaus.jackson.annotate.JsonAnyGetter;
+import org.codehaus.jackson.annotate.JsonAnySetter;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.annotate.JsonPropertyOrder;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@JsonPropertyOrder({
+ "id",
+ "default",
+ "items",
+ "description",
+ "name",
+ "enum",
+ "properties",
+ "required",
+ "notes",
+ "access",
+ "type"
+})
+public class ApiPropertyDefn implements Serializable
+{
+
+ @JsonProperty("id")
+ private String id;
+ @JsonProperty("default")
+ private String defaultValue;
+ @JsonProperty("items")
+ private ApiPropertyDefn items;
+ @JsonProperty("description")
+ private String description;
+ @JsonProperty("name")
+ private String name;
+ @JsonProperty("enum")
+ private List