/*******************************************************************************
* Copyright (c) 2006-2010 eBay Inc. 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
*******************************************************************************/
package org.ebayopensource.turmeric.eclipse.resources.util;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.ebayopensource.turmeric.eclipse.core.logging.SOALogger;
import org.ebayopensource.turmeric.eclipse.core.resources.constants.SOAProjectConstants;
import org.ebayopensource.turmeric.eclipse.core.resources.constants.SOAProjectConstants.ServiceLayer;
import org.ebayopensource.turmeric.eclipse.core.resources.constants.SOAProjectConstants.SupportedProjectType;
import org.ebayopensource.turmeric.eclipse.resources.model.ISOAProject;
import org.ebayopensource.turmeric.eclipse.resources.model.ISOAProjectResolver;
import org.ebayopensource.turmeric.eclipse.resources.model.SOAConsumerMetadata;
import org.ebayopensource.turmeric.eclipse.resources.model.SOAImplMetadata;
import org.ebayopensource.turmeric.eclipse.resources.model.SOAIntfMetadata;
import org.ebayopensource.turmeric.eclipse.resources.model.SOAIntfProject;
import org.ebayopensource.turmeric.eclipse.resources.model.SOAProjectEclipseMetadata;
import org.ebayopensource.turmeric.eclipse.resources.model.SOAProjectResolverFactory;
import org.ebayopensource.turmeric.eclipse.soatools.configtool.ConfigTool;
import org.ebayopensource.turmeric.eclipse.utils.lang.StringUtil;
import org.ebayopensource.turmeric.eclipse.utils.plugin.WorkspaceUtil;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
/**
* The Class SOAServiceUtil.
*
* @author smathew
*
* Utility class for processing project properties The Project does not carry
* information like the WSDL location. It will be calculated using the existing
* project properties. The core calculation of the majority of functions inside
* this class is based on the properties file. It handles all SOA interface,
* implementation and consumer projects. Any new utility for these projects
* should be added here.
*/
public class SOAServiceUtil {
private static final SOALogger logger = SOALogger.getLogger();
/**
* Compute admin name.
*
* @param serviceName the service name
* @param domainClassifier the domain classifier
* @param serviceVersion the service version
* @return the string
*/
public static String computeAdminName(String serviceName, String domainClassifier,
String serviceVersion) {
if (StringUtils.isEmpty(serviceName))
return SOAProjectConstants.EMPTY_STRING;
StringBuffer result = new StringBuffer();
if (StringUtils.isNotBlank(domainClassifier)) {
//Marketplace organization
result.append(StringUtils.capitalize(domainClassifier));
}
result.append(serviceName);
result.append(SOAProjectConstants.MAJOR_VERSION_PREFIX);
result.append(SOAServiceUtil.getServiceMajorVersion(serviceVersion));
return result.toString();
}
/**
* Generate interface class name.
*
* @param adminName the admin name
* @param servicePackageName the service package name
* @return the string
*/
public static String generateInterfaceClassName(String adminName,
String servicePackageName) {
return StringUtils.isBlank(servicePackageName) ? adminName
: servicePackageName + SOAProjectConstants.CLASS_NAME_SEPARATOR + adminName;
}
/**
* Generate package name prefix.
*
* @param targetNamespace the target namespace
* @return the string
*/
public static String generatePackageNamePrefix(String targetNamespace) {
if (StringUtils.isNotBlank(targetNamespace)) {
return ConfigTool.getDefaultPackageNameFromNamespace(targetNamespace);
}
return "";
}
/**
* Generate service package name.
*
* @param serviceName the service name
* @param packageNamePrefix the package name prefix
* @return the string
*/
public static String generateServicePackageName(String serviceName, String packageNamePrefix) {
if (StringUtils.isBlank(serviceName))
return StringUtil.toString(packageNamePrefix);
return StringUtil.toString(packageNamePrefix,
SOAProjectConstants.CLASS_NAME_SEPARATOR, serviceName
.toLowerCase(Locale.US));
}
/**
* Generate service impl class name.
*
* @param serviceName the service name
* @param adminName the admin name
* @param targetNamespace the target namespace
* @return the string
*/
public static String generateServiceImplClassName(String serviceName,String adminName, String targetNamespace) {
return generateServiceImplPackageName(serviceName, adminName,
generatePackageNamePrefix(targetNamespace));
}
/**
* Generate service impl package name.
*
* @param serviceName the service name
* @param adminName the admin name
* @param packageNamePrefix the package name prefix
* @return the string
*/
public static String generateServiceImplPackageName(String serviceName, String adminName, String packageNamePrefix) {
if (StringUtils.isBlank(packageNamePrefix))
return "";
if (StringUtils.isBlank(serviceName))
return StringUtil.toString(packageNamePrefix,
SOAProjectConstants.CLASS_NAME_SEPARATOR,
SOAProjectConstants.IMPL_PROJECT_SUFFIX.toLowerCase(),
".Service", SOAProjectConstants.IMPL_PROJECT_SUFFIX);
return StringUtil.toString(packageNamePrefix,
SOAProjectConstants.CLASS_NAME_SEPARATOR, serviceName
.toLowerCase(),
SOAProjectConstants.CLASS_NAME_SEPARATOR,
SOAProjectConstants.IMPL_PROJECT_SUFFIX.toLowerCase(),
SOAProjectConstants.CLASS_NAME_SEPARATOR, adminName,
SOAProjectConstants.IMPL_PROJECT_SUFFIX);
}
/**
* Gets the WSDL from the given interface project, It scans the project and
* look for the WSDL in the designated location if the project is created
* from WSDL. Remember Now SOA supports only services from WSDL. After the
* above mentioned checks it calls the method
*
* @param project the project
* @return the wsdl file
* @link {@link SOAServiceUtil}{@link #getWsdlFile(IProject, String)}
*/
public static IFile getWsdlFile(SOAIntfProject project) {
if (SOALogger.DEBUG)
logger.entering(project);
IFile result = null;
SOAIntfMetadata metadata = project.getMetadata();
SOAProjectEclipseMetadata eclipseMetadata = project
.getEclipseMetadata();
if (metadata.getSourceType().equals(
SOAProjectConstants.InterfaceSourceType.WSDL)) {
if (SOALogger.DEBUG)
logger.debug("The source type of this intf project is WSDL->",
project.getProject());
result = getWsdlFile(eclipseMetadata.getProject(), metadata
.getServiceName());
}
if (SOALogger.DEBUG)
logger.exiting(result);
return result;
}
/**
* Wrapper over the linked method. Does not check if the service was created
* from WSDL or java. Client to check it. First it find out the project in
* the work space with the given name and will invoke the linked method.
*
* @param serviceName the service name
* @return the wsdl file
* @link {@link SOAServiceUtil}{@link #getWsdlFile(IProject, String)}
*/
public static IFile getWsdlFile(String serviceName) {
if (SOALogger.DEBUG)
logger.entering(serviceName);
IProject project = WorkspaceUtil.getProject(serviceName);
final IFile result = getWsdlFile(project, serviceName);
if (SOALogger.DEBUG)
logger.exiting(result);
return result;
}
/**
* Gets the WSDL from the given eclipse project, It scans the project and
* look for the WSDL in the designated location. It just looks for the WSDL
* in the given eclipse project and does not have any SOA specific logic
* except for the location. If the project is null and is not accessible
* this will return null, so that way it is null safe but clients are
* supposed to handle the null graciously.
*
* @param project the project
* @param serviceName the service name
* @return the wsdl file
*/
public static IFile getWsdlFile(final IProject project,
final String serviceName) {
if (SOALogger.DEBUG)
logger.entering(project, serviceName);
IFile result = null;
try {
if (project == null || project.isAccessible() == false
|| serviceName == null)
return result;
return result = project.getFile(SOAIntfProject.META_SRC_WSDL
+ WorkspaceUtil.PATH_SEPERATOR + serviceName
+ WorkspaceUtil.PATH_SEPERATOR + serviceName + ".wsdl");
} finally {
if (SOALogger.DEBUG)
logger.exiting(result);
}
}
/**
* Gets the sOA eclipse metadata.
*
* @param project the project
* @return the sOA eclipse metadata
*/
public static SOAProjectEclipseMetadata getSOAEclipseMetadata(
IProject project) {
return SOAProjectEclipseMetadata.create(project.getName(), project
.getLocation().removeLastSegments(1));
}
/**
* Loads the SOA project from the given eclipse project, first it checks the
* type of project that is whether it is an interface, implementation or
* consumer and then load the rest of the project values from the
* corresponding configuration file(properties file). For implementation
* projects, the service configuration might not be loaded properly, because
* the interface project name is missing. In such a case, please load the
* service configuration yourself.
*
* @param project the project
* @param natureId the nature id
* @return the iSOA project
* @throws Exception the exception
*/
public static ISOAProject loadSOAProject(final IProject project,
String natureId)
throws Exception {
if (SOALogger.DEBUG)
logger.entering(project);
ISOAProject result = null;
if (project == null || project.exists() == false
|| project.isAccessible() == false)
return result;
project.refreshLocal(IResource.DEPTH_INFINITE, null);
final SOAProjectEclipseMetadata eclipseMetadata = getSOAEclipseMetadata(project);
if (SOALogger.DEBUG)
logger.debug("Loading turmeric project->", project);
final ISOAProjectResolver<?> resolver = SOAProjectResolverFactory.getSOAProjectResolver(
natureId);
if (resolver != null)
result = resolver.loadProject(eclipseMetadata);
else
logger.warning("can not find project resolver for nature ID: ", natureId);
if (SOALogger.DEBUG)
logger.exiting(result);
return result;
}
/**
* Loads SOAIntfMedata from service_intf_project.properties. Pure Wrapper
* over the linked method.
*
* @param metadata the metadata
* @return the sOA intf metadata
* @throws IOException Signals that an I/O exception has occurred.
* @throws CoreException the core exception
* @see {@link SOAServiceUtil}{@link #getSOAIntfMetadata(SOAProjectEclipseMetadata, SOAIntfMetadata)}
*/
public static SOAIntfMetadata getSOAIntfMetadata(
SOAProjectEclipseMetadata metadata) throws IOException,
CoreException {
return getSOAIntfMetadata(metadata, null);
}
/**
* Loads the SOA interface project properties from the given meta data
* object. It can tolerate a null SOAIntfMetadata but meta data is not
* supposed to be null. Not null safe, Clients should handle the exceptions.
* It does not fail with an invalid properties file meaning an absence of a
* property will not cause this function to fail, It just makes the
* corresponding property empty.
*
* @param metadata the metadata
* @param intfMetadata the intf metadata
* @return the sOA intf metadata
* @throws IOException Signals that an I/O exception has occurred.
* @throws CoreException the core exception
*/
public static SOAIntfMetadata getSOAIntfMetadata(
SOAProjectEclipseMetadata metadata, SOAIntfMetadata intfMetadata)
throws IOException, CoreException {
if (SOALogger.DEBUG)
logger.entering(metadata, intfMetadata);
if (intfMetadata == null) {
intfMetadata = SOAIntfMetadata
.create(SOAProjectConstants.InterfaceSourceType.JAVA);
}
final IFile file = SOAIntfUtil.getIntfProjectPropFile(metadata
.getProject());
if (file.isAccessible() == false) {
logger
.warning("The interface project's property file[", file
.getLocation(),
"] is not accessible, returning an empty instance of SOAIntfMetadata.");
return SOAIntfMetadata
.create(SOAProjectConstants.InterfaceSourceType.JAVA);
}
final Properties properties = new Properties();
InputStream io = null;
try {
io = file.getContents();
properties.load(io);
if (SOAProjectConstants.PROPS_INTF_SOURCE_TYPE_WSDL
.equals(StringUtils.trim(properties
.getProperty(SOAProjectConstants.PROPS_INTF_SOURCE_TYPE)))) {
intfMetadata
.setSourceType(SOAProjectConstants.InterfaceSourceType.WSDL);
}
final String typeNamespace = StringUtils.trim(properties
.getProperty(SOAProjectConstants.PROPS_KEY_TYPE_NAMESPACE));
if (StringUtils.isNotBlank(typeNamespace)) {
intfMetadata.setTypeNamespace(typeNamespace);
}
if(properties.containsKey(SOAProjectConstants.PROP_KEY_SERVICE_VERSION)) {
intfMetadata.setServiceVersion(StringUtils.trim(properties.getProperty(
SOAProjectConstants.PROP_KEY_SERVICE_VERSION)));
}
if(properties.containsKey(SOAProjectConstants.PROP_KEY_SERVICE_INTERFACE_CLASS_NAME)) {
intfMetadata.setServiceInterface(StringUtils.trim(properties.getProperty(
SOAProjectConstants.PROP_KEY_SERVICE_INTERFACE_CLASS_NAME)));
}
if(properties.containsKey(SOAProjectConstants.PROP_KEY_SERVICE_LAYER)) {
intfMetadata.setServiceLayer(StringUtils.trim(properties.getProperty(
SOAProjectConstants.PROP_KEY_SERVICE_LAYER)));
}
if(properties.containsKey(SOAProjectConstants.PROP_KEY_NON_XSD_FORMATS)) {
intfMetadata.setServiceNonXSDProtocols(StringUtils.trim(properties.getProperty(
SOAProjectConstants.PROP_KEY_NON_XSD_FORMATS)));
}
final String strTypeFolding = StringUtils.trim(properties
.getProperty(SOAProjectConstants.PROPS_KEY_TYPE_FOLDING));
intfMetadata.setTypeFolding(Boolean.valueOf(strTypeFolding));
final String domainName = StringUtils.trim(properties
.getProperty(SOAProjectConstants.PROPS_SERVICE_DOMAIN_NAME));
if (StringUtils.isNotBlank(domainName)) {
intfMetadata.setServiceDomainName(domainName);
}
final String nsPart = StringUtils.trim(properties
.getProperty(SOAProjectConstants.PROPS_SERVICE_NAMESPACE_PART));
if (StringUtils.isNotBlank(nsPart)) {
intfMetadata.setServiceNamespacePart(nsPart);
}
} finally {
IOUtils.closeQuietly(io);
}
if (SOALogger.DEBUG)
logger.exiting(intfMetadata);
return intfMetadata;
}
/**
* Loads meta data from service_impl_project.properties Pure Wrapper over
* the linked method.
*
* @param metadata the metadata
* @return the sOA impl metadata
* @throws IOException Signals that an I/O exception has occurred.
* @throws CoreException the core exception
* @see {@link SOAServiceUtil}{@link #getSOAImplMetadata(IProject))}
*/
public static SOAImplMetadata getSOAImplMetadata(
SOAProjectEclipseMetadata metadata) throws IOException,
CoreException {
if (SOALogger.DEBUG)
logger.entering(metadata);
final SOAImplMetadata implMetadata = getSOAImplMetadata(metadata
.getProject());
if (SOALogger.DEBUG)
logger.exiting(implMetadata);
return implMetadata;
}
/**
* Loads the SOA implementation project properties from the given IProject
* object. It can tolerate a null SOAImplMetadata but meta data is not
* supposed to be null. Not null safe, Clients should handle the exceptions.
* It does not fail with an invalid properties file meaning an absence of a
* property will not cause this function to fail, It just makes the
* corresponding property empty.
*
* @param project the project
* @return the sOA impl metadata
* @throws IOException Signals that an I/O exception has occurred.
* @throws CoreException the core exception
*/
public static SOAImplMetadata getSOAImplMetadata(final IProject project)
throws IOException, CoreException {
if (SOALogger.DEBUG)
logger.entering(project);
final IFile file = project
.getFile(SOAProjectConstants.PROPS_FILE_SERVICE_IMPL);
if (file.isAccessible() == false) {
logger
.warning("The implementation project's property file[",
file.getLocation(),
"] is not accessible, returning an empty instance of SOAImplMetadata.");
return SOAImplMetadata.create(project.getName(),
SOAProjectConstants.DEFAULT_BASE_CONSUMER_SOURCE_DIRECTORY);
}
Properties properties = new Properties();
InputStream io = null;
SOAImplMetadata implMetadata = null;
try {
io = file.getContents();
properties.load(io);
final String baseConsumerDir = StringUtils.trim(properties
.getProperty(SOAProjectConstants.PROPS_IMPL_BASE_CONSUMER_SRC_DIR));
implMetadata = SOAImplMetadata.create(project.getName(),
baseConsumerDir);
} finally {
IOUtils.closeQuietly(io);
}
if (SOALogger.DEBUG)
logger.exiting(implMetadata);
return implMetadata;
}
/**
* This function creates the SOA related meta data for the given project
* from service_consumer_project.properties. Pure Wrapper over the linked
* method.
*
* @param metadata the metadata
* @return the sOA consumer metadata
* @throws IOException Signals that an I/O exception has occurred.
* @throws CoreException Suresh changed this
* @see {@link SOAServiceUtil}{@link #getSOAConsumerMetadata(IProject))}
*/
public static SOAConsumerMetadata getSOAConsumerMetadata(
SOAProjectEclipseMetadata metadata) throws IOException,
CoreException {
if (SOALogger.DEBUG)
logger.entering(metadata);
SOAConsumerMetadata consumerMetadata = getSOAConsumerMetadata(metadata
.getProject());
if (SOALogger.DEBUG)
logger.exiting(consumerMetadata);
return consumerMetadata;
}
/**
* Loads the SOA consumer project properties from the given IProject object.
* It can tolerate a null SOAConsumerMetadata but meta data is not supposed
* to be null. Not null safe, Clients should handle the exceptions. It does
* not fail with an invalid properties file meaning an absence of a property
* will not cause this function to fail, It just makes the corresponding
* property empty.
*
* @param project the project
* @return the sOA consumer metadata
* @throws IOException Signals that an I/O exception has occurred.
* @throws CoreException the core exception
*/
public static SOAConsumerMetadata getSOAConsumerMetadata(
final IProject project) throws IOException, CoreException {
if (SOALogger.DEBUG)
logger.entering(project);
final IFile file = project
.getFile(SOAProjectConstants.PROPS_FILE_SERVICE_CONSUMER);
Properties properties = new Properties();
InputStream input = null;
try {
input = file.getContents();
properties.load(input);
} finally {
IOUtils.closeQuietly(input);
}
String baseConsumerDir = StringUtils.trim(properties
.getProperty(SOAProjectConstants.PROPS_IMPL_BASE_CONSUMER_SRC_DIR));
SOAConsumerMetadata consumerMetadata = SOAConsumerMetadata.create(
project.getName(), baseConsumerDir);
final String envMapper = StringUtils.trim(properties.getProperty(
SOAProjectConstants.PROPS_ENV_MAPPER));
if (StringUtils.isNotBlank(envMapper)) {
consumerMetadata.setEnvMapper(envMapper);
}
final String clientName = properties.getProperty(
SOAProjectConstants.PROPS_KEY_CLIENT_NAME, project.getName());
final String consumerId = properties.getProperty(
SOAProjectConstants.PROPS_KEY_CONSUMER_ID, null);
consumerMetadata.setClientName(clientName);
consumerMetadata.setConsumerId(consumerId);
consumerMetadata.setZeroConfig(Boolean.valueOf(StringUtils.trim(
properties.getProperty(SOAProjectConstants.PROPS_SUPPORT_ZERO_CONFIG,
Boolean.FALSE.toString()))));
if (SOALogger.DEBUG)
logger.exiting(consumerMetadata);
return consumerMetadata;
}
/**
* Returns true if the given project has one of the natures passed. Not null
* safe. If the project is not accessible, the API will fail and clients are
* supposed to handle it.
*
* @param project the project
* @param natureIDs the nature i ds
* @return true, if successful
* @throws CoreException the core exception
*/
public static boolean hasNatures(final IProject project,
final String... natureIDs) throws CoreException {
for (String natureId : natureIDs) {
if (project.hasNature(natureId)) {
return true;
}
}
return false;
}
/**
* Checks if the given string is a valid service layer string, Now two
* checks are performed, empty and non numeric.
*
* @param layer the layer
* @return true, if is valid service layer
*/
public static boolean isValidServiceLayer(final String layer) {
return StringUtils.isNotBlank(layer)
&& StringUtils.isNumeric(layer) == false;
}
/**
* It first use the string based non SOA specific basic validation and it it
* passes then it will do the domain specific validation using the linked
* method for both the layers passed.
*
* @param layer the layer
* @param dependencyLayer the dependency layer
* @return true, if successful
* @see SOAServiceUtil#validateServiceLayer(ServiceLayer, ServiceLayer)
*/
public static boolean validateServiceLayer(final String layer,
final String dependencyLayer) {
if (isValidServiceLayer(layer) == false
|| isValidServiceLayer(dependencyLayer) == false)
return false;
return validateServiceLayer(ServiceLayer.value(layer), ServiceLayer
.value(dependencyLayer));
}
/**
* Does the SOA specific service layer validation specified in the SOA ERD.
* The API is null safe and returns false if any of the layer passed is
* null.
*
* @param layer the layer
* @param dependencyLayer the dependency layer
* @return true, if successful
*/
public static boolean validateServiceLayer(final ServiceLayer layer,
final ServiceLayer dependencyLayer) {
if (SOALogger.DEBUG)
logger.entering(layer, dependencyLayer);
boolean result = false;
try {
if (layer == null || dependencyLayer == null)
return result;
// This is eBay Marketplaces service layering policy for SOA
// Framework
// 1.8+ as per ERD
// The relationship is greater than or equal (ordinal value) unless
// its
// the Business layer.
if (ServiceLayer.BUSINESS.ordinal() == layer.ordinal()
&& ServiceLayer.BUSINESS.ordinal() == dependencyLayer
.ordinal())
return result;
return result = layer.ordinal() >= dependencyLayer.ordinal();
} finally {
if (SOALogger.DEBUG)
logger.exiting(result);
}
}
/**
* Gets the consumer folder for a given eclipse project. This API works for
* both implementation projects and consumer projects. The meta data object
* will have the directory name and it makes an eclipse API call on the
* project.
*
* @param project the project
* @param projectType the project type
* @return the base consumer folder
* @throws IOException Signals that an I/O exception has occurred.
* @throws CoreException the core exception
*/
public static IFolder getBaseConsumerFolder(final IProject project,
SupportedProjectType projectType)
throws IOException, CoreException {
if (SupportedProjectType.IMPL.equals(projectType)) {
final SOAImplMetadata metadata = getSOAImplMetadata(project);
if (metadata != null
&& StringUtils.isNotBlank(metadata.getBaseConsumerSrcDir())) {
return project.getFolder(metadata.getBaseConsumerSrcDir());
}
} else if (SupportedProjectType.CONSUMER.equals(projectType)) {
final SOAConsumerMetadata metadata = getSOAConsumerMetadata(project);
if (metadata != null
&& StringUtils.isNotBlank(metadata.getBaseConsumerSrcDir())) {
return project.getFolder(metadata.getBaseConsumerSrcDir());
}
}
return project.getFolder(SOAProjectConstants.FOLDER_SRC);
}
/**
* Gets the invokeable service layer.
*
* @param layerName the layer name
* @return the invokeable service layer
*/
public static List<String> getInvokeableServiceLayer(String layerName){
List<String> layers = new ArrayList<String>();
ServiceLayer layer = ServiceLayer.value(layerName);
switch (layer) {
case COMMON:
layers.add(ServiceLayer.COMMON.name());
break;
case INTERMEDIATE:
layers.add(ServiceLayer.COMMON.name());
layers.add(ServiceLayer.INTERMEDIATE.name());
break;
case BUSINESS:
layers.add(ServiceLayer.COMMON.name());
layers.add(ServiceLayer.INTERMEDIATE.name());
break;
}
return layers;
}
/**
* Get the major version of the given service version.
* @param version
* @return
*/
public static String getServiceMajorVersion(String version) {
if (StringUtils.isBlank(version))
return "1";
return StringUtils.substringBefore(version, ".");
}
}