/*
* Copyright (c) 2005-2009, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file 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 org.wso2.carbon.registry.extensions.handlers;
import org.apache.xerces.xni.parser.XMLInputSource;
import org.wso2.carbon.registry.core.RegistryConstants;
import org.wso2.carbon.registry.core.config.RegistryContext;
import org.wso2.carbon.registry.core.utils.RegistryUtils;
import org.wso2.carbon.registry.extensions.handlers.utils.SchemaProcessor;
import org.wso2.carbon.registry.extensions.handlers.utils.SchemaValidator;
import org.wso2.carbon.registry.extensions.handlers.utils.WSDLProcessor;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.jdbc.handlers.RequestContext;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.ResourcePath;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.registry.extensions.utils.CommonUtil;
import org.wso2.carbon.registry.extensions.utils.WSDLValidationInfo;
import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@SuppressWarnings("unused")
public class ZipWSDLMediaTypeHandler extends WSDLMediaTypeHandler {
// <handler class="org.wso2.carbon.registry.extensions.handlers.ZipWSDLMediaTypeHandler">
// <property name="wsdlMediaType">application/wsdl+xml</property>
// <property name="schemaMediaType">application/xsd+xml</property>
// <!--property name="disableWSDLValidation">true</property>
// <property name="disableSchemaValidation">true</property>
// <property name="wsdlExtension">.wsdl</property>
// <property name="schemaExtension">.xsd</property>
// <property name="archiveExtension">.gar</property>
// <property name="tempFilePrefix">wsdl</property-->
// <property name="schemaLocationConfiguration" type="xml">
// <location>/governance/schemas/</location>
// </property>
// <property name="wsdlLocationConfiguration" type="xml">
// <location>/governance/wsdls/</location>
// </property>
// <filter class="org.wso2.carbon.registry.core.jdbc.handlers.filters.MediaTypeMatcher">
// <property name="mediaType">application/vnd.wso2.governance-archive</property>
// </filter>
// </handler>
private String wsdlMediaType = "application/wsdl+xml";
private String wsdlExtension = ".wsdl";
private String xsdMediaType = "application/xsd+xml";
private String xsdExtension = ".xsd";
private String archiveExtension = ".gar";
private String tempFilePrefix = "wsdl";
private boolean disableWSDLValidation = false;
private boolean disableSchemaValidation = false;
private static final Log log = LogFactory.getLog(ZipWSDLMediaTypeHandler.class);
public void put(RequestContext requestContext) throws RegistryException {
if (!CommonUtil.isUpdateLockAvailable()) {
return;
}
CommonUtil.acquireUpdateLock();
try {
Resource resource = requestContext.getResource();
String path = requestContext.getResourcePath().getPath();
try {
// If the WSDL is already there, we don't need to re-run this handler unless the content is changed.
// Re-running this handler causes issues with downstream handlers and other behaviour (ex:- lifecycles).
// If you need to do a replace programatically, delete-then-replace.
if (requestContext.getRegistry().resourceExists(path)) {
// TODO: Add logic to compare content, and return only if the content didn't change.
return;
}
} catch (Exception ignore) { }
try {
if (resource != null) {
Object resourceContent = resource.getContent();
InputStream in = new ByteArrayInputStream((byte[]) resourceContent);
File tempFile = File.createTempFile(tempFilePrefix, archiveExtension);
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(tempFile));
try {
byte[] contentChunk = new byte[1024];
int byteCount;
while ((byteCount = in.read(contentChunk)) != -1) {
out.write(contentChunk, 0, byteCount);
}
out.flush();
} finally {
out.close();
}
ZipEntry entry;
Stack<File> fileList = new Stack<File>();
List<String> wsdlUriList = new LinkedList<String>();
int wsdlPathDepth = Integer.MAX_VALUE;
List<String> xsdUriList = new LinkedList<String>();
int xsdPathDepth = Integer.MAX_VALUE;
List<String> uriList = new LinkedList<String>();
File tempDir = new File(tempFile.getAbsolutePath().substring(0,
tempFile.getAbsolutePath().length() - archiveExtension.length()));
makeDir(tempDir);
ZipInputStream zs;
zs = new ZipInputStream(new FileInputStream(tempFile));
try {
entry = zs.getNextEntry();
while (entry != null) {
String entryName = entry.getName();
FileOutputStream os;
File file = new File(tempFile.getAbsolutePath().substring(0,
tempFile.getAbsolutePath().length() -
archiveExtension.length()) + File.separator + entryName);
if (entry.isDirectory()) {
if (!file.exists()) {
makeDirs(file);
fileList.push(file);
}
entry = zs.getNextEntry();
continue;
}
File parentFile = file.getParentFile();
if (!parentFile.exists()) {
makeDirs(parentFile);
}
os = new FileOutputStream(file);
try {
fileList.push(file);
byte[] contentChunk = new byte[1024];
int byteCount;
while ((byteCount = zs.read(contentChunk)) != -1) {
os.write(contentChunk, 0, byteCount);
}
} finally {
os.close();
}
zs.closeEntry();
entry = zs.getNextEntry();
if (entryName != null &&
entryName.toLowerCase().endsWith(wsdlExtension)) {
String uri = tempFile.toURI().toString();
uri = uri.substring(0, uri.length() -
archiveExtension.length()) + "/" + entryName;
if (uri.startsWith("file:")) {
uri = uri.substring(5);
}
while (uri.startsWith("/")) {
uri = uri.substring(1);
}
uri = "file:///" + uri;
if (uri.endsWith("/")) {
uri = uri.substring(0, uri.length() -1);
}
int uriPathDepth = uri.split("/").length;
if (uriPathDepth < wsdlPathDepth) {
wsdlPathDepth = uriPathDepth;
wsdlUriList = new LinkedList<String>();
}
if (wsdlPathDepth == uriPathDepth) {
wsdlUriList.add(uri);
}
} else if (entryName != null &&
entryName.toLowerCase().endsWith(xsdExtension)) {
String uri = tempFile.toURI().toString();
uri = uri.substring(0, uri.length() -
archiveExtension.length()) + "/" + entryName;
if (uri.startsWith("file:")) {
uri = uri.substring(5);
}
while (uri.startsWith("/")) {
uri = uri.substring(1);
}
uri = "file:///" + uri;
if (uri.endsWith("/")) {
uri = uri.substring(0, uri.length() -1);
}
int uriPathDepth = uri.split("/").length;
if (uriPathDepth < xsdPathDepth) {
xsdPathDepth = uriPathDepth;
xsdUriList = new LinkedList<String>();
}
if (xsdPathDepth == uriPathDepth) {
xsdUriList.add(uri);
}
} else if (entryName != null) {
String uri = tempFile.toURI().toString();
uri = uri.substring(0, uri.length() -
archiveExtension.length()) + "/" + entryName;
if (uri.startsWith("file:")) {
uri = uri.substring(5);
}
while (uri.startsWith("/")) {
uri = uri.substring(1);
}
uri = "file:///" + uri;
if (uri.endsWith("/")) {
uri = uri.substring(0, uri.length() -1);
}
uriList.add(uri);
}
}
} finally {
zs.close();
}
if (wsdlPathDepth < Integer.MAX_VALUE) {
Map<String, String> wsdlMap = new LinkedHashMap<String, String>();
for (String uri : wsdlUriList) {
wsdlMap.put(uri, addWSDLFromZip(requestContext, uri));
}
onPutCompleted(path, wsdlMap, uriList, requestContext);
}
if (xsdPathDepth < Integer.MAX_VALUE) {
Map<String, String> schemaMap = new LinkedHashMap<String, String>();
for (String uri : xsdUriList) {
schemaMap.put(uri, addSchemaFromZip(requestContext, uri));
}
onPutCompleted(path, schemaMap, uriList, requestContext);
}
if(wsdlUriList.isEmpty() && xsdUriList.isEmpty()){
throw new RegistryException("No WSDLs or Schemas found in the given WSDL archive");
}
delete(tempFile);
while(!fileList.isEmpty()) {
delete(fileList.pop());
}
delete(tempDir);
}
} catch (IOException e) {
throw new RegistryException("Error occurred while unpacking Governance Archive", e);
}
requestContext.setProcessingComplete(true);
} finally {
CommonUtil.releaseUpdateLock();
}
}
/**
* Method that runs the WSDL upload procedure.
*
* @param requestContext the request context for the import/put operation
* @param uri the URL from which the WSDL is imported
*
* @return the path at which the WSDL was uploaded to
*
* @throws RegistryException if the operation failed.
*/
protected String addWSDLFromZip(RequestContext requestContext, String uri)
throws RegistryException {
if (uri != null) {
Resource local = requestContext.getRegistry().newResource();
local.setMediaType(wsdlMediaType);
requestContext.setSourceURL(uri);
requestContext.setResource(local);
String path = requestContext.getResourcePath().getPath();
if (path.lastIndexOf("/") != -1) {
path = path.substring(0, path.lastIndexOf("/"));
} else {
path = "";
}
String wsdlName = uri;
if (wsdlName.lastIndexOf("/") != -1) {
wsdlName = wsdlName.substring(wsdlName.lastIndexOf("/"));
} else {
wsdlName = "/" + wsdlName;
}
path = path + wsdlName;
requestContext.setResourcePath(new ResourcePath(path));
WSDLProcessor wsdlProcessor = new WSDLProcessor(requestContext);
return wsdlProcessor.addWSDLToRegistry(requestContext, uri, local, false, true,
disableWSDLValidation);
}
return null;
}
/**
* Method that runs the Schema upload procedure.
*
* @param requestContext the request context for the import/put operation
* @param uri the URL from which the Schema is imported
*
* @return the path at which the schema was uploaded to
*
* @throws RegistryException if the operation failed.
*/
protected String addSchemaFromZip(RequestContext requestContext, String uri)
throws RegistryException {
if (uri != null) {
Resource local = requestContext.getRegistry().newResource();
local.setMediaType(xsdMediaType);
requestContext.setSourceURL(uri);
requestContext.setResource(local);
String path = requestContext.getResourcePath().getPath();
if (path.lastIndexOf("/") != -1) {
path = path.substring(0, path.lastIndexOf("/"));
} else {
path = "";
}
String xsdName = uri;
if (xsdName.lastIndexOf("/") != -1) {
xsdName = xsdName.substring(xsdName.lastIndexOf("/"));
} else {
xsdName = "/" + xsdName;
}
path = path + xsdName;
requestContext.setResourcePath(new ResourcePath(path));
WSDLValidationInfo validationInfo = null;
try {
if (!disableSchemaValidation) {
validationInfo = SchemaValidator.validate(new XMLInputSource(null, uri, null));
}
} catch (Exception e) {
throw new RegistryException("Exception occured while validating the schema" , e);
}
SchemaProcessor schemaProcessor =
new SchemaProcessor(requestContext, validationInfo);
String savedName = schemaProcessor
.importSchemaToRegistry(requestContext, path,
getChrootedLocation(requestContext.getRegistryContext()), true);
String parentPath = RegistryUtils.getParentPath(requestContext.getResourcePath().getPath());
if (parentPath.endsWith(RegistryConstants.PATH_SEPARATOR)) {
requestContext.setActualPath(parentPath + savedName);
} else {
requestContext.setActualPath(parentPath + RegistryConstants.PATH_SEPARATOR + savedName);
}
return requestContext.getActualPath();
}
return null;
}
private String getChrootedLocation(RegistryContext registryContext) {
return RegistryUtils.getAbsolutePath(registryContext,
RegistryConstants.GOVERNANCE_REGISTRY_BASE_PATH + schemaLocation);
}
public void importResource(RequestContext context) {
// We don't support importing .gar files. This is meant only for uploading WSDL files
// and imports from the local filesystem.
log.warn("The imported Governance Web Archive will not be extracted. To extract the content"
+ " upload the archive from the file system.");
}
public void setWsdlMediaType(String wsdlMediaType) {
this.wsdlMediaType = wsdlMediaType;
}
public void setWsdlExtension(String wsdlExtension) {
this.wsdlExtension = wsdlExtension;
}
public void setSchemaMediaType(String xsdMediaType) {
this.xsdMediaType = xsdMediaType;
}
public void setSchemaExtension(String xsdExtension) {
this.xsdExtension = xsdExtension;
}
public void setArchiveExtension(String archiveExtension) {
this.archiveExtension = archiveExtension;
}
public void setTempFilePrefix(String tempFilePrefix) {
this.tempFilePrefix = tempFilePrefix;
}
public void setDisableWSDLValidation(String disableWSDLValidation) {
this.disableWSDLValidation = Boolean.toString(true).equals(disableWSDLValidation);
}
public void setDisableSchemaValidation(String disableSchemaValidation) {
this.disableSchemaValidation = Boolean.toString(true).equals(disableSchemaValidation);
}
}