Java tutorial
/** * Copyright 2013 - 2017 WaveMaker, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License 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.wavemaker.app.build.maven.plugin.handler; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.apache.commons.lang3.StringUtils; import org.json.JSONException; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.wavemaker.app.build.servicedef.ServiceDefGenerator; import com.wavemaker.app.build.exception.ServiceDefGenerationException; import com.wavemaker.commons.WMRuntimeException; import com.wavemaker.commons.io.File; import com.wavemaker.commons.io.FilterOn; import com.wavemaker.commons.io.Folder; import com.wavemaker.commons.io.Resources; import com.wavemaker.commons.json.JSONUtils; import com.wavemaker.commons.servicedef.model.ServiceDefinition; import com.wavemaker.commons.util.IOUtils; import com.wavemaker.tools.apidocs.tools.core.model.Swagger; /** * @author <a href="mailto:sunil.pulugula@wavemaker.com">Sunil Kumar</a> * @since 29/4/16 */ public class VariableServiceDefGenerationHandler implements AppBuildHandler { private static final Logger logger = LoggerFactory.getLogger(VariableServiceDefGenerationHandler.class); private static final String SERVICE_DEFS = "servicedefs"; private static final String WM_SERVICE_VARIABLE = "wm.ServiceVariable"; private static final String WEBSOCKET_VARIABLE = "wm.WebSocketVariable"; private static final String DESIGN_TIME_FOLDER = "designtime"; private static final String API_EXTENSION = "_API.json"; private static final String REST_SERVICE_API_EXTENSION = "_API_REST_SERVICE.json"; private static final String WEBSOCKET_SERVICE_API_EXTENSION = "_API_WEBSOCKET_SERVICE.json"; public static final String SERVICE_SRC_DIR = "src"; private static String SERVICE_DEF_RESOURCE_NAME = "{}-service-definitions.json"; private static final String[] SWAGGER_EXTENSIONS = new String[] { WEBSOCKET_SERVICE_API_EXTENSION, REST_SERVICE_API_EXTENSION, API_EXTENSION }; private final String servicesDirectory = "services"; private final Folder servicesFolder; private final Folder rootFolder; private ExecutorService executorService = Executors.newFixedThreadPool(5); private Map<String, Future<Map<String, ServiceDefinition>>> serviceVsServiceDefs = new HashMap<>(); private Map<String, Map<String, ServiceDefinition>> filteredServiceDefinitions = new ConcurrentHashMap<>(); public VariableServiceDefGenerationHandler(Folder rootFolder) { this.rootFolder = rootFolder; this.servicesFolder = rootFolder.getFolder(servicesDirectory); } @Override public void handle() { init(); generateServiceDefs(); persistServiceDefs(); } private void init() { buildServiceDefsForAllServices(servicesFolder); } private void buildServiceDefsForAllServices(final Folder servicesFolder) { if (servicesFolder.exists()) { List<Folder> serviceFolders = servicesFolder.list().folders().fetchAll(); if (serviceFolders.size() > 0) { for (final Folder serviceFolder : serviceFolders) { serviceVsServiceDefs.put(serviceFolder.getName(), executorService.submit(new Callable<Map<String, ServiceDefinition>>() { @Override public Map<String, ServiceDefinition> call() throws Exception { return buildServiceDefs(serviceFolder); } })); } } for (String service : serviceVsServiceDefs.keySet()) { handleFutureIfException(serviceVsServiceDefs.get(service)); } } } private Map<String, ServiceDefinition> buildServiceDefs(final Folder serviceFolder) { Folder designFolder = serviceFolder.getFolder(DESIGN_TIME_FOLDER); Swagger swagger = null; boolean swaggerFileFound = false; for (String swaggerExtension : SWAGGER_EXTENSIONS) { File swaggerFile = designFolder.getFile(designFolder.getParent().getName() + swaggerExtension); if (swaggerFile.exists()) { swaggerFileFound = true; swagger = unmarshallSwagger(swaggerFile); break; } } if (!swaggerFileFound) { logger.error("Swagger File does not exist for service {}", serviceFolder.getName()); } try { return swagger != null ? new ServiceDefGenerator(swagger).generate() : new HashMap<String, ServiceDefinition>(); } catch (ServiceDefGenerationException e) { throw new WMRuntimeException( "Failed to build service def for service " + swagger.getInfo().getServiceId(), e); } } private void generateServiceDefs() { Resources<File> files = rootFolder.find().files().exclude(FilterOn.antPattern("/app/prefabs/**")) .include(FilterOn.names().ending(".variables.json")); Collection<Callable> callables = new ArrayList<>(); Collection<Future> futures = new ArrayList<>(); try { for (final File file : files) { callables.add(new Callable<Object>() { @Override public Object call() throws Exception { try { generateServiceDefs(file); } catch (JSONException e) { logger.error( "Failed to build service definitions for variable json file " + file.getName()); } return this; } }); } for (Callable callable : callables) { futures.add(executorService.submit(callable)); } for (Future<Object> future : futures) { handleFutureIfException(future); } } finally { executorService.shutdown(); } } private <V> V handleFutureIfException(Future<V> future) { Throwable t = null; V v = null; try { v = future.get(); } catch (CancellationException ce) { t = ce; } catch (ExecutionException ee) { t = ee; } catch (InterruptedException e) { t = e; } if (t != null) { throw new WMRuntimeException(t); } return v; } private void generateServiceDefs(final File file) throws JSONException, ExecutionException, InterruptedException { String s = file.getContent().asString(); if (StringUtils.isBlank(s)) { return; } JSONObject jsonObject = new JSONObject(s); Iterator keys = jsonObject.keys(); while (keys.hasNext()) { String key = (String) keys.next(); JSONObject o = (JSONObject) jsonObject.get(key); if (o.has("category")) { String category = o.getString("category"); if (!(WM_SERVICE_VARIABLE.equals(category) || WEBSOCKET_VARIABLE.equals(category))) { continue; } if (!o.has("operationId")) { logger.warn("Service variable " + key + " does not have operation id "); continue; } if (!o.has("service")) { logger.warn("Service variable " + key + " does not have service name property "); continue; } String operationId = o.getString("operationId"); String service = o.getString("service"); if (serviceVsServiceDefs.get(service) == null) { logger.warn("Service " + service + " does not exist for the service variable" + key); continue; } synchronized (filteredServiceDefinitions) { if (!filteredServiceDefinitions.containsKey(service)) { filteredServiceDefinitions.put(service, new ConcurrentHashMap<String, ServiceDefinition>()); } } final Map<String, ServiceDefinition> serviceDefinitions = serviceVsServiceDefs.get(service).get(); if (serviceDefinitions.containsKey(operationId)) { ServiceDefinition serviceDefinition = serviceDefinitions.get(operationId); Map<String, ServiceDefinition> serviceDefinitionMap = filteredServiceDefinitions.get(service); serviceDefinitionMap.put(operationId, serviceDefinition); } } } } protected void persistServiceDefs() { for (final String service : filteredServiceDefinitions.keySet()) { if (filteredServiceDefinitions.get(service).size() > 0) { persistServiceDefs(service, filteredServiceDefinitions.get(service)); } } } protected void persistServiceDefs(final String serviceId, final Map<String, ServiceDefinition> serviceDefMap) { File serviceDefResource = getServiceDefResource(serviceId); OutputStream outputStream = null; try { outputStream = serviceDefResource.getContent().asOutputStream(); JSONUtils.toJSON(outputStream, serviceDefMap, true); } catch (IOException e) { throw new WMRuntimeException( "Failed to persist service definition in resource " + serviceDefResource.getName(), e); } finally { org.apache.commons.io.IOUtils.closeQuietly(outputStream); } } protected File getServiceDefResource(final String serviceId) { final Folder serviceFolder = servicesFolder.getFolder(serviceId).getFolder(SERVICE_SRC_DIR); File file = serviceFolder.getFolder(SERVICE_DEFS) .getFile(SERVICE_DEF_RESOURCE_NAME.replace("{}", serviceId)); if (!file.exists()) { file.createIfMissing(); } return file; } protected Swagger unmarshallSwagger(File file) { InputStream is = null; try { is = file.getContent().asInputStream(); Swagger swagger = JSONUtils.toObject(is, Swagger.class); return swagger; } catch (Exception e) { throw new WMRuntimeException("Failed to parse swagger file ", e); } finally { IOUtils.closeSilently(is); } } }