/*
* Copyright (c) 2006, WSO2 Inc. (http://www.wso2.org) 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.
* 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.resource.services.utils;
import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.util.AXIOMUtil;
import org.apache.axiom.om.xpath.AXIOMXPath;
import org.apache.axis2.context.MessageContext;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jaxen.JaxenException;
import org.wso2.carbon.registry.common.CommonConstants;
import org.wso2.carbon.registry.common.ResourceData;
import org.wso2.carbon.registry.common.utils.UserUtil;
import org.wso2.carbon.registry.core.Association;
import org.wso2.carbon.registry.core.Collection;
import org.wso2.carbon.registry.core.Registry;
import org.wso2.carbon.registry.core.RegistryConstants;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.ResourcePath;
import org.wso2.carbon.registry.core.config.RemoteConfiguration;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.pagination.PaginationContext;
import org.wso2.carbon.registry.core.pagination.PaginationUtils;
import org.wso2.carbon.registry.core.secure.AuthorizationFailedException;
import org.wso2.carbon.registry.core.session.UserRegistry;
import org.wso2.carbon.registry.resource.beans.CollectionContentBean;
import org.wso2.carbon.registry.resource.beans.ContentBean;
import org.wso2.carbon.registry.resource.beans.ContentDownloadBean;
import org.wso2.carbon.registry.resource.download.DownloadManagerService;
import org.wso2.carbon.utils.CarbonUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.xml.namespace.QName;
public class ContentUtil {
private static final Log log = LogFactory.getLog(ContentUtil.class);
private static final String IMPORT_SCHEMA_LOCATION = "//xs:schema/xs:import[@schemaLocation]";
private static final String INCLUDE_SCHEMA_LOCATION = "//xs:schema/xs:include[@schemaLocation]";
private static DownloadManagerService downloadManagerService;
public static void setDownloadManagerService(DownloadManagerService downloadManagerService) {
ContentUtil.downloadManagerService = downloadManagerService;
}
public static CollectionContentBean getCollectionContent(String path,
UserRegistry registry) throws Exception {
try {
Resource resource = registry.get(path);
if (!(resource instanceof Collection)) {
String msg = "Attempted to get collection content from " +
"a non-collection resource " + path;
log.error(msg);
throw new RegistryException(msg);
}
Collection collection = (Collection) resource;
String[] childPaths = collection.getChildren();
MessageContext messageContext = MessageContext.getCurrentMessageContext();
String[] paginatedResult;
if (messageContext != null && PaginationUtils.isPaginationHeadersExist(messageContext)) {
int rowCount = childPaths.length;
try {
PaginationUtils.setRowCount(messageContext, Integer.toString(rowCount));
PaginationContext paginationContext = PaginationUtils.initPaginationContext(messageContext);
int start = paginationContext.getStart();
int count = paginationContext.getCount();
int startIndex;
if (start == 1) {
startIndex = 0;
} else {
startIndex = start;
}
if (rowCount < start + count) {
paginatedResult = new String[rowCount - startIndex];
System.arraycopy(childPaths, startIndex, paginatedResult, 0, (rowCount - startIndex));
} else {
paginatedResult = new String[count];
System.arraycopy(childPaths, startIndex, paginatedResult, 0,count);
}
} finally {
PaginationContext.destroy();
}
childPaths = paginatedResult;
}
CollectionContentBean bean = new CollectionContentBean();
bean.setChildPaths(childPaths);
bean.setChildCount(childPaths.length);
bean.setCollectionTypes(getCollectionTypes());
if (registry.getRegistryContext() != null) {
List remoteInstances = registry.getRegistryContext().
getRemoteInstances();
String[] instances = new String[remoteInstances.size()];
for(int i=0; i<instances.length; i++) {
instances[i] = ((RemoteConfiguration)remoteInstances.get(i)).getId();
}
bean.setRemoteInstances(instances);
}
ResourcePath resourcePath = new ResourcePath(path);
bean.setPathWithVersion(resourcePath.getPathWithVersion());
bean.setVersionView(!resourcePath.isCurrentVersion());
return bean;
} catch (Exception e) {
String msg = "Failed to get content details of the resource " + path +
". Caused by: " + ((e.getCause() instanceof SQLException) ?
"" : e.getMessage());
log.error(msg, e);
throw new RegistryException(msg, e);
}
}
public static ResourceData[] getResourceData(String[] childPaths,
UserRegistry registry) throws Exception {
List <ResourceData> resourceDataList = new ArrayList <ResourceData> ();
for (String childPath : childPaths) {
try {
if (childPath == null || childPath.length() == 0) {
continue;
}
Resource child = registry.get(childPath);
ResourceData resourceData = new ResourceData();
resourceData.setResourcePath(childPath); // + RegistryConstants.VIEW_ACTION);
String[] parts = childPath.split(RegistryConstants.PATH_SEPARATOR);
if (parts.length > 0) {
resourceData.setName(parts[parts.length - 1]);
}
resourceData.setResourceType(child instanceof Collection ?
CommonConstants.COLLECTION : CommonConstants.RESOURCE);
resourceData.setAuthorUserName(child.getAuthorUserName());
resourceData.setDescription(child.getDescription());
resourceData.setAverageRating(registry.getAverageRating(child.getPath()));
Calendar createDateTime = Calendar.getInstance();
createDateTime.setTime(child.getCreatedTime());
resourceData.setCreatedOn(createDateTime);
List mountPoints = child.getPropertyValues("registry.mountpoint");
List targetPoints = child.getPropertyValues("registry.targetpoint");
// List paths = child.getPropertyValues("registry.path");
List actualPaths = child.getPropertyValues("registry.actualpath");
String user = child.getProperty("registry.user");
if (child.getProperty("registry.mount") != null) {
resourceData.setMounted(true);
}
if (child.getProperty("registry.link") != null) {
resourceData.setLink(true);
if(mountPoints != null && targetPoints != null) {
// String mountPoint = (String)mountPoints.get(0);
// String targetPoint = (String)targetPoints.get(0);
// String tempPath;
// if (targetPoint.equals(RegistryConstants.PATH_SEPARATOR) && !childPath.equals(mountPoint)) {
// tempPath = ((String)paths.get(0)).substring(mountPoint.length());
// } else {
// tempPath = targetPoint + ((String)paths.get(0)).substring(mountPoint.length());
// }
String tempPath = (String)actualPaths.get(0);
resourceData.setPutAllowed(
UserUtil.isPutAllowed(registry.getUserName(), tempPath, registry));
resourceData.setDeleteAllowed(UserUtil.isDeleteAllowed(registry.getUserName(),
tempPath, registry));
resourceData.setGetAllowed(UserUtil.isGetAllowed(registry.getUserName(), tempPath, registry));
resourceData.setRealPath(tempPath);
} else if (user != null) {
// Fix for https://wso2.org/jira/browse/REGISTRY-2495
// if (registry.getUserName().equals(user)) {
// resourceData.setPutAllowed(true);
// resourceData.setDeleteAllowed(true);
// resourceData.setGetAllowed(true);
// } else {
resourceData.setPutAllowed(
UserUtil.isPutAllowed(registry.getUserName(), childPath, registry));
resourceData.setDeleteAllowed(
UserUtil.isDeleteAllowed(registry.getUserName(), childPath, registry));
resourceData.setGetAllowed(
UserUtil.isGetAllowed(registry.getUserName(), childPath, registry));
// }
// Mounted resources should be accessed via the link, and we need not set
// the real path.
}
} else {
resourceData.setPutAllowed(UserUtil.isPutAllowed(registry.getUserName(), childPath, registry));
resourceData.setDeleteAllowed(
UserUtil.isDeleteAllowed(registry.getUserName(), childPath, registry));
resourceData.setGetAllowed(
UserUtil.isGetAllowed(registry.getUserName(), childPath, registry));
}
calculateAverageStars(resourceData);
if(child.getProperty("registry.externalLink") != null) {
resourceData.setExternalLink(true);
}
if(child.getProperty("registry.absent") != null){
resourceData.setAbsent(child.getProperty("registry.absent"));
}
resourceDataList.add(resourceData);
} catch (AuthorizationFailedException ignore) {
// if we get an auth failed exception while accessing a child, we simply skip it.
// we are not showing unauthorized resources.
}
}
return resourceDataList.toArray(new ResourceData[resourceDataList.size()]);
}
public static ContentBean getContent(String path, UserRegistry registry) throws Exception {
ResourcePath resourcePath = new ResourcePath(path);
ContentBean bean = new ContentBean();
Resource resource = registry.get(path);
bean.setMediaType(resource.getMediaType());
bean.setCollection(resource instanceof Collection);
bean.setLoggedIn(!RegistryConstants.ANONYMOUS_USER.equals(registry.getUserName()));
bean.setPathWithVersion(resourcePath.getPathWithVersion());
bean.setAbsent(resource.getProperty("registry.absent"));
List mountPoints = resource.getPropertyValues("registry.mountpoint");
List targetPoints = resource.getPropertyValues("registry.targetpoint");
// List paths = resource.getPropertyValues("registry.path");
List actualPaths = resource.getPropertyValues("registry.actualpath");
String user = resource.getProperty("registry.user");
if (resource.getProperty("registry.link") != null) {
if (mountPoints != null && targetPoints != null) {
// String mountPoint = (String)mountPoints.get(0);
// String targetPoint = (String)targetPoints.get(0);
// String tempPath;
// if (targetPoint.equals(RegistryConstants.PATH_SEPARATOR) && !childPath.equals(mountPoint)) {
// tempPath = ((String)paths.get(0)).substring(mountPoint.length());
// } else {
// tempPath = targetPoint + ((String)paths.get(0)).substring(mountPoint.length());
// }
String tempPath = (String)actualPaths.get(0);
bean.setPutAllowed(
UserUtil.isPutAllowed(registry.getUserName(), tempPath, registry));
bean.setRealPath(tempPath);
} else if (user != null) {
// Fix for https://wso2.org/jira/browse/REGISTRY-2495
// if (registry.getUserName().equals(user)) {
// bean.setPutAllowed(true);
// } else {
bean.setPutAllowed(
UserUtil.isPutAllowed(registry.getUserName(), path, registry));
// }
// Mounted resources should be accessed via the link, and we need not set
// the real path.
}
} else {
boolean putAllowed = UserUtil.isPutAllowed(registry.getUserName(), path, registry);
bean.setPutAllowed(putAllowed);
}
bean.setVersionView(!resourcePath.isCurrentVersion());
bean.setContentPath(resourcePath.getCompletePath());
resource.discard();
return bean;
}
private static String[] getCollectionTypes() {
return new String[] {"default", "Axis2 repository", "Synapse repository"};
}
private static void calculateAverageStars(ResourceData resourceData) {
float tempRating = resourceData.getAverageRating() * 1000;
tempRating = Math.round(tempRating);
tempRating = tempRating / 1000;
resourceData.setAverageRating(tempRating);
float averageRating = resourceData.getAverageRating();
String[] averageStars = new String[5];
for (int i = 0; i < 5; i++) {
if (averageRating >= i + 1) {
averageStars[i] = "04";
} else if (averageRating <= i) {
averageStars[i] = "00";
} else {
float fraction = averageRating - i;
if (fraction <= 0.125) {
averageStars[i] = "00";
} else if (fraction > 0.125 && fraction <= 0.375) {
averageStars[i] = "01";
} else if (fraction > 0.375 && fraction <= 0.625) {
averageStars[i] = "02";
} else if (fraction > 0.625 && fraction <= 0.875) {
averageStars[i] = "03";
} else {
averageStars[i] = "04";
}
}
}
resourceData.setAverageStars(averageStars);
}
public static boolean hasAssociations(String path,String type,UserRegistry registry) throws Exception {
if(type == null || path == null) {
return false;
}
Association [] associations = registry.getAssociations(path,type);
for(Association association:associations){
if (association.getAssociationType() != null && association.getAssociationType().equals(type)
&& association.getSourcePath().equals(path)) {
return true;
}
}
return false;
}
public static ContentDownloadBean getContentWithDependencies(String path,UserRegistry registry) throws Exception {
if(downloadManagerService != null) {
return downloadManagerService.getDownloadContent(path,registry);
} else {
return getDownloadContent(path,registry);
}
}
private static ContentDownloadBean getDownloadContent(String path, Registry _registry) throws Exception {
UserRegistry registry = (UserRegistry)_registry;
InputStream zipContentStream = null;
File srcDir = null;
File zipFile = null;
String COLLECTION = "collection";
ByteArrayOutputStream outputStream = null;
ContentDownloadBean zipContent;
try {
if (path == null) {
String msg = "Could not get the resource content. Path is not specified.";
log.error(msg);
return null;
}
ContentDownloadBean bean = GetDownloadContentUtil.getContentDownloadBean(path, registry);
String zipDirPath = CarbonUtils.getCarbonHome() + File.separator + "tmp" + File.separator + bean.toString();
String zipDependencyPath = zipDirPath +File.separator + "dependencies";
String zipPath = zipDirPath + "-zip.zip";
Association[] associations = registry.getAssociations(path,"depends");
if (associations.length != 0) {
srcDir = new File(zipDirPath);
srcDir.mkdir();
new File(zipDependencyPath).mkdir();
zipFile = new File(zipPath);
// Creating artifact file itself
File _tmp = new File(zipDirPath + File.separator + bean.getResourceName());
DataOutputStream _fos = new DataOutputStream(new FileOutputStream(_tmp));
byte[] _bytes = IOUtils.toByteArray(bean.getContent().getInputStream());
createDependencies(associations,registry,zipDependencyPath,path,COLLECTION, new String(_bytes),_fos,true);
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile));
zipDir(zipDirPath, zos);
zos.close();
zipContentStream = new FileInputStream(new File(zipPath));
} else if (bean.getContent() != null) {
zipContentStream = bean.getContent().getInputStream();
} else {
String msg = "The resource content was empty.";
log.error(msg);
return null;
}
if (zipContentStream != null) {
try {
outputStream = new ByteArrayOutputStream();
byte[] contentChunk = new byte[1024];
int byteCount;
while ((byteCount = zipContentStream.read(contentChunk)) != -1) {
outputStream.write(contentChunk, 0, byteCount);
}
outputStream.flush();
} finally {
zipContentStream.close();
if (outputStream != null) {
outputStream.close();
}
}
}
zipContent = new ContentDownloadBean();
DataSource contentSource = new InputStreamBasedDataSource(new ByteArrayInputStream(outputStream.toByteArray()));
DataHandler content = new DataHandler(contentSource);
zipContent.setContent(content);
} catch (RegistryException e) {
String msg = "Failed to get resource content. " + e.getMessage();
log.error(msg, e);
return null;
} finally {
FileUtils.deleteQuietly(srcDir);
FileUtils.deleteQuietly(zipFile);
}
return zipContent;
}
private static void createDependencies(Association[] associations, UserRegistry registry, String zipDependencyPath,
String scrPath, String COLLECTION,String content,DataOutputStream srcOutputStream,boolean isMasterArtifact) throws Exception {
for (Association associationBean : associations) {
if (isADependency(associationBean, registry, scrPath, COLLECTION)) {
ContentDownloadBean dependencyBean = GetDownloadContentUtil.getContentDownloadBean(associationBean.getDestinationPath(), registry);
InputStream dependencyContentStream = dependencyBean.getContent().getInputStream();
File tmp = new File(zipDependencyPath + File.separator + dependencyBean.getResourceName());
DataOutputStream fos = new DataOutputStream(new FileOutputStream(tmp));
byte[] bytes = IOUtils.toByteArray(dependencyContentStream);
createDependencies(registry.getAssociations(associationBean.getDestinationPath(),"depends"),
registry,zipDependencyPath,associationBean.getDestinationPath(),COLLECTION,new String(bytes),fos,false);
}
}
if(scrPath.endsWith(".wsdl") || scrPath.endsWith(".xsd")) {
OMElement srcOMElement = AXIOMUtil.stringToOM(content);
updateSchemaImports(srcOMElement, isMasterArtifact, IMPORT_SCHEMA_LOCATION);
updateSchemaImports(srcOMElement, isMasterArtifact, INCLUDE_SCHEMA_LOCATION);
updateWSDLImports(srcOMElement,isMasterArtifact);
IOUtils.write(srcOMElement.toString().getBytes(), srcOutputStream);
} else {
IOUtils.write(content.getBytes(), srcOutputStream);
}
}
private static boolean isADependency(Association associationBean,UserRegistry registry,String scrPath,String COLLECTION) throws Exception {
if(associationBean.getDestinationPath() == null ||
(!registry.resourceExists(associationBean.getDestinationPath()))){
return false;
}
ResourceData resourceData = ContentUtil.getResourceData(new String[]{associationBean.getDestinationPath()}, registry)[0];
boolean isCollection = resourceData.getResourceType().equals(COLLECTION);
return (associationBean.getAssociationType() != null && associationBean.getAssociationType().equals("depends")
&& associationBean.getSourcePath().equals(scrPath) && !isCollection);
}
private static OMElement updateSchemaImports(OMElement omElement, boolean isMasterArtifact, String xpath)
throws JaxenException {
AXIOMXPath xPath = new AXIOMXPath(xpath);
// "http://schemas.xmlsoap.org/wsdl/"
xPath.addNamespace("xs", "http://www.w3.org/2001/XMLSchema");
Object result = xPath.evaluate(omElement);
if(!(result instanceof ArrayList)){
return omElement;
}
List list = (ArrayList)result;
for (Object obj : list) {
OMElement _import = (OMElement) obj;
OMAttribute attribute = _import.getAttribute(new QName("schemaLocation"));
String newValue = isMasterArtifact ? "dependencies" + attribute.getAttributeValue().substring(attribute.getAttributeValue().lastIndexOf("/"))
:attribute.getAttributeValue().substring(attribute.getAttributeValue().lastIndexOf("/")+1);
attribute.setAttributeValue(newValue);
}
return omElement;
}
private static OMElement updateWSDLImports(OMElement omElement,boolean isMasterArtifact) throws JaxenException {
AXIOMXPath xPath = new AXIOMXPath("//wsd:import[@location]");
xPath.addNamespace("wsd", "http://schemas.xmlsoap.org/wsdl/");
Object result = xPath.evaluate(omElement);
if(!(result instanceof ArrayList)){
return omElement;
}
List list = (ArrayList) result;
for (Object obj : list) {
OMElement _import = (OMElement) obj;
OMAttribute attribute = _import.getAttribute(new QName("location"));
String newValue = isMasterArtifact ? "dependencies" + attribute.getAttributeValue().substring(attribute.getAttributeValue().lastIndexOf("/"))
:attribute.getAttributeValue().substring(attribute.getAttributeValue().lastIndexOf("/")+1);
attribute.setAttributeValue(newValue);
}
return omElement;
}
private static void zipDir(String dirToZip, ZipOutputStream zos) throws org.wso2.carbon.registry.api.RegistryException {
try {
File zipDir = new File(dirToZip);
String[] dirList = zipDir.list();
byte[] readBuffer = new byte[1024];
int bytesIn = 0;
for (int i = 0; i < dirList.length; i++) {
File f = new File(zipDir,dirList[i]);
if(f.isDirectory()) {
zipDir(f.getPath(),zos);
continue;
} else {
FileInputStream fis = new FileInputStream(f.getPath());
ZipEntry anEntry = new ZipEntry(f.getPath().contains("dependencies") ? "dependencies" + File.separator + f.getName():f.getName());
zos.putNextEntry(anEntry);
while ((bytesIn = fis.read(readBuffer)) != -1) {
zos.write(readBuffer, 0, bytesIn);
}
zos.flush();
fis.close();
}
}
} catch (Exception e) {
throw new org.wso2.carbon.registry.api.RegistryException("Error occurred while zipping the file");
}
}
}