/**
* Copyright © 2012 Alcatel-Lucent.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* Licensed to you 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.alu.e3.prov.service;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import org.apache.commons.io.IOUtils;
import org.springframework.core.io.Resource;
import com.alu.e3.common.camel.ExchangeConstantKeys;
import com.alu.e3.common.logging.Category;
import com.alu.e3.common.logging.CategoryLogger;
import com.alu.e3.common.logging.CategoryLoggerFactory;
import com.alu.e3.common.tools.BundleTools;
import com.alu.e3.prov.restapi.ExchangeData;
import com.alu.e3.prov.restapi.model.Api;
import com.alu.e3.prov.restapi.model.ResourceItem;
import com.alu.e3.prov.restapi.model.SchemaValidationEnum;
import com.alu.e3.prov.restapi.model.Validation;
import com.alu.e3.prov.restapi.model.Validation.Schema;
import freemarker.cache.URLTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
public class ApiJarBuilder implements IApiJarBuilder {
private static final CategoryLogger LOG = CategoryLoggerFactory.getLogger(ApiJarBuilder.class, Category.PROV);
private static final String MANIFEST_TEMPLATE_PATH = "ftl/META-INF/MANIFEST.MF.ftl";
private static final String ROUTE_TEMPLATE_PATH = "ftl/META-INF/spring/route-context.xml.ftl";
private static final String RESOURCES_FOLDER_PATH_IN_JAR = "resources";
private Configuration fmConfiguration = null;
protected int bufferSize = 128 * 1024;
private Resource soap11;
private Resource soap12;
private Resource xml;
// for Jar generation in disk
private boolean generateJarInFile = false;
private String workingDir;
private String archiveDir;
public ApiJarBuilder(Resource soap11, Resource soap12, Resource xml) {
this();
this.soap11 = soap11;
this.soap12 = soap12;
this.xml = xml;
}
public ApiJarBuilder() {
fmConfiguration = new Configuration();
// fmConfiguration.setCacheStorage(new NoCacheStorage());
fmConfiguration.setLocalizedLookup(false);
fmConfiguration.setTemplateLoader(new URLTemplateLoader() {
@Override
protected URL getURL(String name) {
return ApiJarBuilder.class.getClassLoader().getResource(name);
}
});
}
/*
* (non-Javadoc)
*
* @see
* com.alu.e3.prov.restapi.IApiJarBuilder#build(com.alu.e3.prov.restapi.
* model.Api, java.util.Map)
*/
@Override
public byte[] build(Api api, ExchangeData exchange) {
final Map<Object, Object> variablesMap = new HashMap<Object, Object>();
variablesMap.put("exchange", exchange);
byte[] jarBytes = null;
ByteArrayOutputStream baos = null;
JarOutputStream jos = null;
try {
baos = new ByteArrayOutputStream();
jos = new JarOutputStream(baos);
List<JarEntryData> entries = new ArrayList<JarEntryData>();
doGenXML(entries, api, variablesMap);
doGenManifest(entries, api, variablesMap);
doGenResources(entries, api, variablesMap);
for (JarEntryData anEntry : entries) {
jos.putNextEntry(anEntry.jarEntry);
jos.write(anEntry.bytes);
}
// the close is necessary before getting bytes
jos.close();
jarBytes = baos.toByteArray();
if (this.generateJarInFile) {
// generate Jar in Disk for debug only
doGenJar(jarBytes, api, variablesMap);
}
} catch (Exception e) {
if(LOG.isErrorEnabled()) {
LOG.error("Error building the jar for apiID:" + api.getId(), e);
}
} finally {
if (jos != null)
try {
jos.close();
} catch (IOException e) {
LOG.error("Error closing stream", e);
}
if (baos != null)
try {
baos.close();
} catch (IOException e) {
LOG.error("Error closing stream", e);
}
}
return jarBytes;
}
protected void doGenManifest(List<JarEntryData> entries, Api api, Map<Object, Object> variablesMap) throws IOException, TemplateException {
Template template = fmConfiguration.getTemplate(MANIFEST_TEMPLATE_PATH);
StringWriter buffer = new StringWriter();
template.process(variablesMap, buffer);
buffer.flush();
if (LOG.isDebugEnabled())
LOG.debug(buffer.getBuffer().toString());
addJarEntry(entries, buffer.getBuffer().toString().getBytes("UTF-8"), "META-INF/MANIFEST.MF");
}
protected void doGenXML(List<JarEntryData> entries, Api api, Map<Object, Object> variablesMap) throws IOException, TemplateException {
Template template = fmConfiguration.getTemplate(ROUTE_TEMPLATE_PATH);
StringWriter buffer = new StringWriter();
template.process(variablesMap, buffer);
buffer.flush();
if (LOG.isDebugEnabled())
LOG.debug(buffer.getBuffer().toString());
addJarEntry(entries, buffer.getBuffer().toString().getBytes("UTF-8"), "META-INF/spring/route-context.xml");
}
protected void doGenResources(List<JarEntryData> entries, Api api, Map<Object, Object> variablesMap) throws UnsupportedEncodingException, IOException {
if (api.getValidation() != null) {
Validation val = api.getValidation();
Schema schema = val.getSchema();
if (schema != null) {
// loop on schema resources and store them on files
StringBuffer buf = new StringBuffer();
List<ResourceItem> resources = schema.getResourcesList();
int resourcesCount = resources.size();
for (int i = 0; i < resourcesCount; i++) {
ResourceItem item = resources.get(i);
if (item != null) {
boolean isMain = item.isIsMain();
String fileName = item.getName();
if (isMain) {
fileName = "main." + fileName;
}
// log file name
buf.append(fileName);
if ((i + 1) < resourcesCount) {
buf.append(";");
}
addJarEntry(entries, item.getGrammar().getBytes("UTF-8"), RESOURCES_FOLDER_PATH_IN_JAR + File.separator + fileName);
}
}
// if the validation is WSDL, we need to add the schemas to
// validate the SOAP envelop
if (schema.getType() == SchemaValidationEnum.WSDL) {
addSOAPResources(entries, buf, RESOURCES_FOLDER_PATH_IN_JAR);
}
// write resources.list file
addJarEntry(entries, buf.toString().getBytes("UTF-8"), RESOURCES_FOLDER_PATH_IN_JAR + File.separator + "resources.list");
}
}
}
protected void doGenJar(byte[] jarBytes, Api api, Map<Object, Object> variablesMap) throws Exception {
ExchangeData data = (ExchangeData) variablesMap.get("exchange");
String jarName = data.getProperties().get(ExchangeConstantKeys.E3_API_ID_ENCODED.toString()) + "-" + data.getProperties().get(ExchangeConstantKeys.E3_PROVISION_ID.toString()) + ".jar";
File file = new File(workingDir + File.separator + archiveDir + File.separator + jarName);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
BundleTools.byteArray2File(jarBytes, file);
}
protected void addJarEntry(List<JarEntryData> entries, byte[] bytes, String entryName) throws IOException {
JarEntry anEntry = new JarEntry(entryName);
JarEntryData data = new JarEntryData();
data.bytes = bytes;
data.jarEntry = anEntry;
entries.add(data);
}
private void addSOAPResources(List<JarEntryData> entries, StringBuffer buf, String dirPath) throws IOException {
// load xml schema
InputStream xmlIn = this.xml.getInputStream();
String xmlName = this.xml.getFilename();
addJarEntry(entries, IOUtils.toByteArray(xmlIn), dirPath + File.separator + xmlName);
// log filename
buf.append(";");
buf.append(xmlName);
buf.append(";");
// load soap 1.1 schema
InputStream soap11In = this.soap11.getInputStream();
String soap11Name = this.soap11.getFilename();
addJarEntry(entries, IOUtils.toByteArray(soap11In), dirPath + File.separator + soap11Name);
// log filename
buf.append(soap11Name);
buf.append(";");
// load soap 1.2 schema
InputStream soap12In = this.soap12.getInputStream();
String soap12Name = this.soap12.getFilename();
addJarEntry(entries, IOUtils.toByteArray(soap12In), dirPath + File.separator + soap12Name);
// log filename
buf.append(soap12Name);
}
private class JarEntryData {
JarEntry jarEntry;
byte[] bytes;
}
public String getWorkingDir() {
return workingDir;
}
public void setWorkingDir(String workingDir) {
this.workingDir = workingDir;
}
public String getArchiveDir() {
return archiveDir;
}
public void setArchiveDir(String archiveDir) {
this.archiveDir = archiveDir;
}
public boolean isGenerateJarInFile() {
return generateJarInFile;
}
public void setGenerateJarInFile(boolean generateJarInFile) {
this.generateJarInFile = generateJarInFile;
}
}