Java tutorial
/* * ****************************************************************************** * Copyright 2014-2016 Spectra Logic Corporation. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"). You may not use * this file except in compliance with the License. A copy of the License is located at * * http://www.apache.org/licenses/LICENSE-2.0 * * or in the "license" file accompanying this file. * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. * **************************************************************************** */ package com.spectralogic.ds3autogen.python; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.spectralogic.ds3autogen.api.CodeGenerator; import com.spectralogic.ds3autogen.api.FileUtils; import com.spectralogic.ds3autogen.api.models.apispec.Ds3ApiSpec; import com.spectralogic.ds3autogen.api.models.apispec.Ds3Request; import com.spectralogic.ds3autogen.api.models.apispec.Ds3Type; import com.spectralogic.ds3autogen.api.models.docspec.Ds3DocSpec; import com.spectralogic.ds3autogen.python.generators.client.BaseClientGenerator; import com.spectralogic.ds3autogen.python.generators.client.ClientModelGenerator; import com.spectralogic.ds3autogen.python.generators.request.*; import com.spectralogic.ds3autogen.python.generators.response.*; import com.spectralogic.ds3autogen.python.generators.type.BaseTypeGenerator; import com.spectralogic.ds3autogen.python.generators.type.TypeModelGenerator; import com.spectralogic.ds3autogen.python.helpers.PythonHelper; import com.spectralogic.ds3autogen.python.model.client.BaseClient; import com.spectralogic.ds3autogen.python.model.commands.CommandSet; import com.spectralogic.ds3autogen.python.model.request.BaseRequest; import com.spectralogic.ds3autogen.python.model.response.BaseResponse; import com.spectralogic.ds3autogen.python.model.type.TypeDescriptor; import com.spectralogic.ds3autogen.utils.Helper; import com.spectralogic.ds3autogen.utils.collections.GuavaCollectors; import freemarker.template.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.nio.file.Path; import java.nio.file.Paths; import static com.spectralogic.ds3autogen.python.utils.GeneratorUtils.hasFileObjectListPayload; import static com.spectralogic.ds3autogen.utils.ConverterUtil.isEmpty; import static com.spectralogic.ds3autogen.utils.ConverterUtil.removeUnusedTypes; import static com.spectralogic.ds3autogen.utils.Ds3RequestClassificationUtil.*; public class PythonCodeGenerator implements CodeGenerator { private static final Logger LOG = LoggerFactory.getLogger(PythonCodeGenerator.class); private static final Path BASE_PROJECT_PATH = Paths.get("ds3"); private final Configuration config = new Configuration(Configuration.VERSION_2_3_23); private FileUtils fileUtils; private Path destDir; public PythonCodeGenerator() throws TemplateModelException { config.setDefaultEncoding("UTF-8"); config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); config.setClassForTemplateLoading(PythonCodeGenerator.class, "/tmpls"); config.setSharedVariable("pythonHelper", PythonHelper.getInstance()); config.setSharedVariable("helper", Helper.getInstance()); } @Override public void generate(final Ds3ApiSpec spec, final FileUtils fileUtils, final Path destDir, final Ds3DocSpec docSpec) { this.fileUtils = fileUtils; this.destDir = destDir; try { final ImmutableList<Ds3Request> requests = spec.getRequests(); final ImmutableMap<String, Ds3Type> typeMap = removeUnusedTypes(spec.getTypes(), spec.getRequests()); generateCommands(requests, typeMap, docSpec); } catch (final Exception e) { e.printStackTrace(); } } /** * Generates the ds3.py python code which includes: request handlers, response handlers, * response payload descriptors, and the client */ private void generateCommands(final ImmutableList<Ds3Request> ds3Requests, final ImmutableMap<String, Ds3Type> typeMap, final Ds3DocSpec docSpec) throws IOException, TemplateException { if (isEmpty(ds3Requests)) { LOG.info("There are no requests to generate"); return; } final ImmutableList<BaseRequest> baseRequests = toRequestModelList(ds3Requests, docSpec); final ImmutableList<BaseResponse> baseResponses = toResponseModelList(ds3Requests); final ImmutableList<TypeDescriptor> baseTypes = toTypeDescriptorList(typeMap); final ImmutableList<BaseClient> clientCommands = toClientCommands(ds3Requests, docSpec); final CommandSet commandSet = new CommandSet(baseRequests, baseResponses, baseTypes, clientCommands); final Template tmpl = config.getTemplate("python/commands/all_commands.ftl"); final Path path = toBaseProjectPath("ds3.py"); LOG.info("Getting OutputStream for file: " + path.toString()); try (final OutputStream outStream = fileUtils.getOutputFile(path); final Writer writer = new OutputStreamWriter(outStream)) { tmpl.process(commandSet, writer); } } /** * Generates the python models for the client commands */ protected static ImmutableList<BaseClient> toClientCommands(final ImmutableList<Ds3Request> ds3Requests, final Ds3DocSpec docSpec) { if (isEmpty(ds3Requests)) { return ImmutableList.of(); } return ds3Requests.stream().map(request -> toClientCommand(request, docSpec)) .collect(GuavaCollectors.immutableList()); } /** * Generates the python model for a client command */ protected static BaseClient toClientCommand(final Ds3Request ds3Request, final Ds3DocSpec docSpec) { final ClientModelGenerator<?> clientGenerator = new BaseClientGenerator(); return clientGenerator.generate(ds3Request, docSpec); } /** * Generates the python models for type descriptors, which are used to describe expected responses */ protected static ImmutableList<TypeDescriptor> toTypeDescriptorList( final ImmutableMap<String, Ds3Type> typeMap) { if (isEmpty(typeMap)) { return ImmutableList.of(); } return typeMap.values().stream().filter(type -> isEmpty(type.getEnumConstants())) //Do not generate descriptors for enums .map(ds3Type -> toTypeDescriptor(ds3Type, typeMap)).collect(GuavaCollectors.immutableList()); } /** * Converts a Ds3Type into a python model descriptor */ protected static TypeDescriptor toTypeDescriptor(final Ds3Type ds3Type, final ImmutableMap<String, Ds3Type> typeMap) { final TypeModelGenerator<?> typeGenerator = getTypeGenerator(); return typeGenerator.generate(ds3Type, typeMap); } /** * Retrieves the Type Descriptor Generator associated with the Ds3Type */ protected static TypeModelGenerator<?> getTypeGenerator() { return new BaseTypeGenerator(); } /** * Converts a file name into the path containing said file within the base project path */ protected Path toBaseProjectPath(final String fileName) { return destDir.resolve(BASE_PROJECT_PATH + "/" + fileName); } /** * Converts all Ds3Requests into the python request handler models */ protected static ImmutableList<BaseRequest> toRequestModelList(final ImmutableList<Ds3Request> ds3Requests, final Ds3DocSpec docSpec) { if (isEmpty(ds3Requests)) { return ImmutableList.of(); } return ds3Requests.stream().map(request -> toRequestModel(request, docSpec)) .collect(GuavaCollectors.immutableList()); } /** * Converts a Ds3Request into a python request handler model */ protected static BaseRequest toRequestModel(final Ds3Request ds3Request, final Ds3DocSpec docSpec) { final RequestModelGenerator<?> requestGenerator = getRequestGenerator(ds3Request); return requestGenerator.generate(ds3Request, docSpec); } /** * Retrieves the Request Generator associated with the Ds3Request */ protected static RequestModelGenerator<?> getRequestGenerator(final Ds3Request ds3Request) { if (isGetObjectAmazonS3Request(ds3Request)) { return new GetObjectRequestGenerator(); } if (isAmazonCreateObjectRequest(ds3Request)) { return new PutObjectRequestGenerator(); } if (hasFileObjectListPayload(ds3Request) || isMultiFileDeleteRequest(ds3Request) || isCompleteMultiPartUploadRequest(ds3Request)) { return new ObjectsPayloadGenerator(); } if (isCreateMultiPartUploadPartRequest(ds3Request) || isGetBlobPersistenceRequest(ds3Request) || isBulkReplicateRequest(ds3Request)) { return new StringPayloadGenerator(); } return new BaseRequestGenerator(); } /** * Converts all Ds3Requests into the python response handler models */ protected static ImmutableList<BaseResponse> toResponseModelList(final ImmutableList<Ds3Request> ds3Requests) { if (isEmpty(ds3Requests)) { return ImmutableList.of(); } return ds3Requests.stream().map(PythonCodeGenerator::toResponseModel) .collect(GuavaCollectors.immutableList()); } /** * Converts a Ds3Request into a python response handler model */ protected static BaseResponse toResponseModel(final Ds3Request ds3Request) { final ResponseModelGenerator<?> responseGenerator = getResponseGenerator(ds3Request); return responseGenerator.generate(ds3Request); } /** * Retrieves the Response Generator associated with the Ds3Request */ protected static ResponseModelGenerator<?> getResponseGenerator(final Ds3Request ds3Request) { if (supportsPaginationRequest(ds3Request)) { return new PaginationResponseGenerator(); } if (isGetObjectAmazonS3Request(ds3Request)) { return new GetObjectResponseGenerator(); } if (isHeadBucketRequest(ds3Request) || isHeadObjectRequest(ds3Request)) { return new HeadResponseGenerator(); } return new BaseResponseGenerator(); } }