Compare commits

...

8 Commits

Author SHA1 Message Date
vdrokov
6a38878300 fix(TESB-28767): Update cxf version 2020-04-23 21:03:53 +03:00
Zhiwei Xue
330d706722 fix(TUP-26809):Job zip should not contain jars from testcase only (#4635) 2020-04-23 18:49:25 +08:00
Emmanuel GALLOIS
9c2f08ec2b feat(TCOMP-1681): manage tacokit components in OSGi/Microservice job export (#4617)
* feat(TCOMP-1681): OSGi export

* feat(TCOMP-1681): OSGi export

* feat(TCOMP-1681): add REPLACE_EXISTING option for plugins.properties

* feat(TCOMP-1681): fix resource filtering

* feat(TCOMP-1681): add new resources to assembly for OSGi

* feat(TCOMP-1681): fix missing deps in microservice export

- some refactorings
- now we add the dep jars from TALEND-INF/dependencies.txt to MAVEN-INF

* feat(TCOMP-1681): add TaCoKit dependency service

* feat(TCOMP-1681): chore export dependency exporter

* feat(TCOMP-1681): add TaCoKit dependency service

- refactor and cleanup code

* feat(TCOMP-1681): class isolation

- refactor and cleanup code
2020-04-23 14:53:03 +08:00
hwang-talend
d7651ea0f4 bugfix(TUP-26796):Error "Can't find filed of null" show in error log (#4627)
bugfix(TUP-26796):Error "Can't find filed of null" show in error log when switch back from Jobscript to Designer
2020-04-23 09:59:44 +08:00
Laurent BOURGEOIS
b97a10e28f fix(TBD-10285):Add contains predicate to expressions (#4613) 2020-04-22 17:40:44 +02:00
pyzhou
c9b43d7c67 fix(TDI-44051):add the real value to the db name (#4621)
* fix(TDI-44051):add the real value to the db name

* set dbName as name when db column is null

* workaround

* change back name
2020-04-22 17:38:31 +08:00
Dmytro Sylaiev
87d3fd7c7d Dsylaiev/tdi 43931 pass full date to independand child job (#4622)
* fix(TDI-43931): Convert long as date from context args

* fix(TDI-43931): Update file root to be up to date

* fix(TDI-43931): Implement fix for tRunJob

* fix(TDI-43931): Mention string parse exception in log warn
2020-04-22 12:03:20 +03:00
sbovsunovskyi
0fecec9635 fix(TDI-44070): Unable to execute the job, receiving "Failed to gener… (#4625)
* fix(TDI-44070): Unable to execute the job, receiving "Failed to generate code." when using tAmazonRedshiftManage component.

* fix(TDI-44070): Unable to execute the job, receiving "Failed to generate code." when using tAmazonRedshiftManage component.
2020-04-21 11:23:21 +03:00
18 changed files with 585 additions and 88 deletions

View File

@@ -665,34 +665,39 @@
<%
} else if(typeToGenerate.equals("java.util.Date")) {
%>
try{
String context_<%=ctxParam.getName()%>_value = context.getProperty("<%=ctxParam.getName()%>");
if (context_<%=ctxParam.getName()%>_value == null){
context_<%=ctxParam.getName()%>_value = "";
}
int context_<%=ctxParam.getName()%>_pos = context_<%=ctxParam.getName()%>_value.indexOf(";");
String context_<%=ctxParam.getName()%>_pattern = "yyyy-MM-dd HH:mm:ss";
if(context_<%=ctxParam.getName()%>_pos > -1){
context_<%=ctxParam.getName()%>_pattern = context_<%=ctxParam.getName()%>_value.substring(0, context_<%=ctxParam.getName()%>_pos);
context_<%=ctxParam.getName()%>_value = context_<%=ctxParam.getName()%>_value.substring(context_<%=ctxParam.getName()%>_pos + 1);
}
try{
if (context_<%=ctxParam.getName()%>_value == null){
context_<%=ctxParam.getName()%>_value = "";
}
int context_<%=ctxParam.getName()%>_pos = context_<%=ctxParam.getName()%>_value.indexOf(";");
String context_<%=ctxParam.getName()%>_pattern = "yyyy-MM-dd HH:mm:ss";
if(context_<%=ctxParam.getName()%>_pos > -1){
context_<%=ctxParam.getName()%>_pattern = context_<%=ctxParam.getName()%>_value.substring(0, context_<%=ctxParam.getName()%>_pos);
context_<%=ctxParam.getName()%>_value = context_<%=ctxParam.getName()%>_value.substring(context_<%=ctxParam.getName()%>_pos + 1);
}
context.<%=ctxParam.getName()%>=(java.util.Date)(new java.text.SimpleDateFormat(context_<%=ctxParam.getName()%>_pattern).parse(context_<%=ctxParam.getName()%>_value));
context.<%=ctxParam.getName()%>=(java.util.Date)(new java.text.SimpleDateFormat(context_<%=ctxParam.getName()%>_pattern).parse(context_<%=ctxParam.getName()%>_value));
} catch(ParseException e) {
} catch(ParseException e) {
try { <% /*try to check if date passed as long also*/ %>
long context_<%=ctxParam.getName()%>_longValue = Long.valueOf(context_<%=ctxParam.getName()%>_value);
context.<%=ctxParam.getName()%> = new java.util.Date(context_<%=ctxParam.getName()%>_longValue);
} catch (NumberFormatException cantParseToLongException) {
<%
if (isLog4jEnabled) {
if (isLog4jEnabled) {
%>
log.warn(String.format("<%=warningMessageFormat %>", "<%=ctxParam.getName() %>", e.getMessage()));
log.warn(String.format("<%=warningMessageFormat %>", "<%=ctxParam.getName() %>", "Can't parse date string: " + e.getMessage() + " and long: " + cantParseToLongException.getMessage()));
<%
} else {
} else {
%>
System.err.println(String.format("<%=warningMessageFormat %>", "<%=ctxParam.getName() %>", e.getMessage()));
System.err.println(String.format("<%=warningMessageFormat %>", "<%=ctxParam.getName() %>", "Can't parse date string: " + e.getMessage() + " and long: " + cantParseToLongException.getMessage()));
<%
}
%>
context.<%=ctxParam.getName()%>=null;
}
}
%>
context.<%=ctxParam.getName()%>=null;
}
<%
} else if(typeToGenerate.equals("Object")||typeToGenerate.equals("String")||typeToGenerate.equals("java.lang.String")) {
%>

View File

@@ -62,6 +62,8 @@ class IndexedRecordToRowStructGenerator {
%>
boolean <%=codeVarIsDynamicInitialized%> = false;
routines.system.Dynamic <%=codeVarDynamic%> = new routines.system.Dynamic();
//Workaround for TDI-44051, TcimpV0 do not need DbmsID
<%=codeVarDynamic%>.setDbmsId("<%=cid%>");
<%
}
@@ -115,10 +117,11 @@ class IndexedRecordToRowStructGenerator {
for (org.apache.avro.Schema.Field dynamicField_<%=cid%> : dynSchema_<%=cid%>.getFields()){
routines.system.DynamicMetadata dynamicMetadata_<%=cid%> = new routines.system.DynamicMetadata();
org.apache.avro.Schema dynamicFieldSchema_<%=cid%> = dynamicField_<%=cid%>.schema();
String dbName = dynamicField_<%=cid%>.getProp("talend.field.dbColumnName");
// set name
dynamicMetadata_<%=cid%>.setName(dynamicField_<%=cid%>.name());
// set db name
dynamicMetadata_<%=cid%>.setDbName(dynamicField_<%=cid%>.name());
dynamicMetadata_<%=cid%>.setDbName(dbName==null?dynamicField_<%=cid%>.name():dbName);
// set nullable
if (org.talend.daikon.avro.AvroUtils.isNullable(dynamicFieldSchema_<%=cid%>)) {
dynamicMetadata_<%=cid%>.setNullable(true);

View File

@@ -9,7 +9,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<cxf.version>3.3.4</cxf.version>
<cxf.version>3.3.6</cxf.version>
<odata.version>4.3.0</odata.version>
<slf4j.version>1.7.12</slf4j.version>
<talend.nexus.url>https://artifacts-oss.talend.com</talend.nexus.url>

View File

@@ -24,6 +24,9 @@
String user = ElementParameterParser.getValue(node, "__USER__");
String node_type = ElementParameterParser.getValue(node, "__NODE_TYPE__");
String node_count = ElementParameterParser.getValue(node, "__NODE_COUNT__");
if (node_count.isEmpty()) {
node_count = "1";
}
boolean isLog4jEnabled = "true".equals(ElementParameterParser.getValue(node.getProcess(), "__LOG4J_ACTIVATE__"));
@@ -88,52 +91,46 @@
.withMasterUsername(<%=user%>)
.withMasterUserPassword(decryptedPwd_<%=cid%>)
.withNodeType(<%=node_type%>)
.withNodeType(<%=node_type%>);
<%
if(new Integer(node_count) > 1){
%>
.withNumberOfNodes(<%=node_count%>)
<%
} else {
%>
.withClusterType("single-node")
<%
}
%>
//advanced settings
<%if(parameterUtil.isValid(parameter_group_name)) {%>
.withClusterParameterGroupName(<%=parameter_group_name%>)
<%}%>
<%if(parameterUtil.isValid(subnet_group_name)) {%>
.withClusterSubnetGroupName(<%=subnet_group_name%>)
if (<%=node_count%> > 1) {
request_<%=cid%> = request_<%=cid%>.withNumberOfNodes(<%=node_count%>);
} else {
request_<%=cid%> = request_<%=cid%>.withClusterType("single-node");
}
//advanced settings
<%if(parameterUtil.isValid(parameter_group_name)) {%>
request_<%=cid%> = request_<%=cid%>.withClusterParameterGroupName(<%=parameter_group_name%>);
<%}%>
<%if(parameterUtil.isValid(subnet_group_name)) {%>
request_<%=cid%> = request_<%=cid%>.withClusterSubnetGroupName(<%=subnet_group_name%>);
<%}%>
<%
if(publicly_accessible) {
%>
request_<%=cid%> = request_<%=cid%>.withPubliclyAccessible(true);
<%if(set_public_ip_address) {%>
request_<%=cid%> = request_<%=cid%>.withElasticIp(<%=elastic_ip%>);
<%}%>
<%
if(publicly_accessible) {
%>
.withPubliclyAccessible(true)
<%if(set_public_ip_address) {%>
.withElasticIp(<%=elastic_ip%>)
<%}%>
<%
} else {
%>
.withPubliclyAccessible(false)
<%
}
%>
<%if(parameterUtil.isValid(availability_zone)) {%>
.withAvailabilityZone(<%=availability_zone%>)
<%}%>
<%if(parameterUtil.isValid(vpc_security_groupids)) {%>
.withVpcSecurityGroupIds(<%=vpc_security_groupids%>.split(","))
<%}%>
;
<%
} else {
%>
request_<%=cid%> = request_<%=cid%>.withPubliclyAccessible(false);
<%
}
%>
<%if(parameterUtil.isValid(availability_zone)) {%>
request_<%=cid%> = request_<%=cid%>.withAvailabilityZone(<%=availability_zone%>);
<%}%>
<%if(parameterUtil.isValid(vpc_security_groupids)) {%>
request_<%=cid%> = request_<%=cid%>.withVpcSecurityGroupIds(<%=vpc_security_groupids%>.split(","));
<%}%>
com.amazonaws.services.redshift.model.Cluster result_<%=cid%> = client_<%=cid%>.createCluster(request_<%=cid%>);
<%if(isLog4jEnabled) {%>

View File

@@ -408,7 +408,11 @@ String inputConnName = null;
%>
obj_<%=cid%> = <%=value %>;
if(obj_<%=cid%>!=null) {
paraList_<%=cid %>.add("--context_param <%=name %>=" + RuntimeUtils.tRunJobConvertContext(obj_<%=cid%>));
if (obj_<%=cid %>.getClass().getName().equals("java.util.Date")) {
paraList_<%=cid %>.add("--context_param <%=name %>=" + ((java.util.Date) obj_<%=cid %>).getTime());
} else {
paraList_<%=cid %>.add("--context_param <%=name %>=" + RuntimeUtils.tRunJobConvertContext(obj_<%=cid%>));
}
} else {
paraList_<%=cid %>.add("--context_param <%=name %>=" + NULL_VALUE_EXPRESSION_IN_COMMAND_STRING_FOR_CHILD_JOB_ONLY);
}

View File

@@ -106,6 +106,8 @@ public final class Expression {
}
}
private static final String CONTAINS = "CONTAINS"; //$NON-NLS-1$
private Expression(String expressionString) {
this.expressionString = expressionString;
}
@@ -306,6 +308,10 @@ public final class Expression {
if ((simpleExpression.contains("SPARK_VERSION["))) { //$NON-NLS-1$
return evaluateSparkVersion(simpleExpression, listParam, currentParam);
}
if ((simpleExpression.contains(CONTAINS))) { //$NON-NLS-1$
return evaluateContains(simpleExpression, listParam);
}
List<String> paraNames = getParaNamesFromIsShowFunc(simpleExpression);
if (paraNames.size() > 0) {
@@ -1064,5 +1070,28 @@ public final class Expression {
}
return false;
}
public static boolean evaluateContains(String simpleExpression, List<? extends IElementParameter> listParam) {
//Split to get param name and param value to look after
String[] splitted = simpleExpression.split(CONTAINS);
if (splitted.length != 2) {
return false;
}
String paramName = splitted[0].trim();
String paramValue = splitted[1].trim();
//Look for the param name in list
IElementParameter param = listParam.stream()
.filter(p -> paramName.equals(p.getName()))
.findAny()
.orElse(null);
if (param == null || ! EParameterFieldType.TABLE.equals(param.getFieldType())) {
return false;
}
// Check if we can find paraValue among table lines
return ((List<Map<String, Object>>) param.getValue()).stream()
.anyMatch(line -> paramValue.equals(line.toString()));
}
}

View File

@@ -1396,9 +1396,11 @@ public class Process extends Element implements IProcess2, IGEFProcess, ILastVer
loadElementParameters(elemParam, pType, param, pType.getName(), paraValue, false);
} else {
boolean canAddElementParameter = false;
boolean isActiveDatabase = false;
String paramName = pType.getName();
if (EParameterName.ACTIVE_DATABASE_DELIMITED_IDENTIFIERS.getName().equals(paramName)) {
canAddElementParameter = true;
isActiveDatabase = true;
}
if (canAddElementParameter) {
param = new ElementParameter(elemParam);
@@ -1406,6 +1408,9 @@ public class Process extends Element implements IProcess2, IGEFProcess, ILastVer
param.setName(pType.getName());
param.setCategory(EComponentCategory.TECHNICAL);
String fieldName = pType.getField();
if (isActiveDatabase && fieldName == null) {
fieldName = EParameterFieldType.TEXT.getName();
}
EParameterFieldType fieldType = null;
if (StringUtils.isNotBlank(fieldName)) {
fieldType = EParameterFieldType.valueOf(fieldName);

View File

@@ -249,6 +249,8 @@ public class JavaProcessUtil {
}
// in case of multiple Version jars in customize modules, descendOrder
highPriorityLinkedSet.addAll(descendingOrderModuleList(jdbcCustomizeModulesSet));
LastGenerationInfo.getInstance().setHighPriorityModuleNeededPerJob(process.getId(), process.getVersion(),
highPriorityLinkedSet);
LastGenerationInfo.getInstance().setHighPriorityModuleNeeded(process.getId(), process.getVersion(),
highPriorityLinkedSet);

View File

@@ -23,6 +23,8 @@
<outputDirectory>${file.separator}</outputDirectory>
<includes>
<include>OSGI-INF/**</include>
<include>TALEND-INF/**</include>
<include>MAVEN-INF/**</include>
</includes>
</fileSet>
<fileSet> <!-- add resources -->

View File

@@ -26,6 +26,8 @@
<outputDirectory>${file.separator}</outputDirectory>
<includes>
<include>OSGI-INF/**</include>
<include>TALEND-INF/**</include>
<include>MAVEN-INF/**</include>
</includes>
</fileSet>

View File

@@ -69,7 +69,7 @@ public abstract class JavaScriptForESBWithMavenManager extends JobJavaScriptOSGI
if ("".equals(resource.getDirectoryName())) { //$NON-NLS-1$
Map<String, Set<URL>> newResourcesMap = new HashMap<String, Set<URL>>();
for (String path : resource.getRelativePathList()) {
if (path.startsWith("OSGI") || path.startsWith(FileConstants.META_INF_FOLDER_NAME)) { //$NON-NLS-1$
if (path.startsWith("OSGI") || path.startsWith(FileConstants.META_INF_FOLDER_NAME)|| path.startsWith("TALEND-INF") || path.startsWith("MAVEN-INF")) { //$NON-NLS-1$
Set<URL> urls = resource.getResourcesByRelativePath(path);
// put OSGI_INF to /src/main/resources/
newResourcesMap.put(IMavenProperties.MAIN_RESOURCES_PATH + path, urls);

View File

@@ -12,9 +12,18 @@
// ============================================================================
package org.talend.repository.ui.wizards.exportjob.scriptsmanager.esb;
import aQute.bnd.header.Attrs;
import aQute.bnd.osgi.Analyzer;
import aQute.bnd.osgi.Clazz;
import aQute.bnd.osgi.Descriptors;
import aQute.bnd.osgi.FileResource;
import aQute.bnd.osgi.Jar;
import aQute.bnd.service.AnalyzerPlugin;
import aQute.bnd.service.Plugin;
import aQute.service.reporter.Reporter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -39,6 +48,8 @@ import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.map.MultiKeyMap;
@@ -54,6 +65,7 @@ import org.talend.commons.utils.io.FilesUtils;
import org.talend.core.CorePlugin;
import org.talend.core.GlobalServiceRegister;
import org.talend.core.PluginChecker;
import org.talend.core.model.components.IComponent;
import org.talend.core.model.general.ModuleNeeded;
import org.talend.core.model.general.Project;
import org.talend.core.model.process.IProcess;
@@ -70,6 +82,7 @@ import org.talend.core.repository.model.ProxyRepositoryFactory;
import org.talend.core.runtime.process.ITalendProcessJavaProject;
import org.talend.core.runtime.process.LastGenerationInfo;
import org.talend.core.runtime.repository.build.BuildExportManager;
import org.talend.core.service.ITaCoKitDependencyService;
import org.talend.core.ui.branding.IBrandingService;
import org.talend.designer.core.ICamelDesignerCoreService;
import org.talend.designer.core.IDesignerCoreService;
@@ -87,19 +100,8 @@ import org.talend.repository.documentation.ExportFileResource;
import org.talend.repository.ui.wizards.exportjob.scriptsmanager.JarBuilder;
import org.talend.repository.ui.wizards.exportjob.scriptsmanager.JobJavaScriptsManager;
import org.talend.repository.utils.EmfModelUtils;
import org.talend.repository.utils.EsbConfigUtils;
import org.talend.repository.utils.TemplateProcessor;
import aQute.bnd.header.Attrs;
import aQute.bnd.osgi.Analyzer;
import aQute.bnd.osgi.Clazz;
import aQute.bnd.osgi.Descriptors;
import aQute.bnd.osgi.FileResource;
import aQute.bnd.osgi.Jar;
import aQute.bnd.service.AnalyzerPlugin;
import aQute.bnd.service.Plugin;
import aQute.service.reporter.Reporter;
/**
* DOC ycbai class global comment. Detailled comment
*/
@@ -258,6 +260,8 @@ public class JobJavaScriptOSGIForESBManager extends JobJavaScriptsManager {
* export current item's dependencies. this used for TDM components specially and need more discussion
* about then
*/
// TCOMP-1681: feature uses this call for feeding a component-runtime compliant MAVEN-INF/repository and
// TALEND-INF/plugins.properties.
BuildExportManager.getInstance().exportOSGIDependencies(osgiResource, processItem);
}
@@ -303,6 +307,15 @@ public class JobJavaScriptOSGIForESBManager extends JobJavaScriptsManager {
if (providedLibResources != null) {
list.add(providedLibResources);
}
// TCOMP-1681: for class isolation and avoid clashes, we remove tacokit dependencies to main classpath.
// However, they're in the scope of ComponentManager.
if (GlobalServiceRegister.getDefault().isServiceRegistered(ITaCoKitDependencyService.class)) {
ITaCoKitDependencyService tckService = (ITaCoKitDependencyService) GlobalServiceRegister.getDefault()
.getService(ITaCoKitDependencyService.class);
if (tckService != null && tckService.hasTaCoKitComponents(tckService.getJobComponents(processItem))) {
list = cleanupResources(tckService.getJobComponents(processItem), list, tckService);
}
}
} catch (ProcessorException e) {
throw e;
} catch (Exception e) {
@@ -339,6 +352,28 @@ public class JobJavaScriptOSGIForESBManager extends JobJavaScriptsManager {
return libResource;
}
private List<ExportFileResource> cleanupResources(Stream<IComponent> components, List<ExportFileResource> resources, ITaCoKitDependencyService service) {
Set<String> tckOnly = service.getTaCoKitOnlyDependencies(components);
final List<ExportFileResource> rmResources = new ArrayList<>();
//This code is nicer but have to reiterate after, so not so efficient
// List<URL> rmDeps = resources.stream()
// .filter(rf -> "lib".equals(rf.getDirectoryName()))
// .map(resource -> resource.getResourcesByRelativePath(""))
// .flatMap(urls -> urls.stream())
// .filter(url -> tckOnly.stream().anyMatch(tck -> url.toString().endsWith(tck)))
// .collect(Collectors.toList());
for (ExportFileResource resource : resources) {
if (!("lib".equals(resource.getDirectoryName()) || "lib-provided".equals(resource.getDirectoryName()))) {
continue;
}
List<URL> rmDeps = resource.getResourcesByRelativePath("").stream()
.filter(url -> tckOnly.stream().anyMatch(tck -> url.toString().endsWith(tck)))
.collect(Collectors.toList());
rmDeps.stream().forEach(dep -> resource.removeResources("", dep));
}
return resources;
}
protected String getIncludeRoutinesPath() {
return USER_ROUTINES_PATH;
}

View File

@@ -118,6 +118,10 @@
class="org.talend.sdk.component.studio.service.TaCoKitUpdateService"
serviceId="ITaCoKitUpdateService">
</Service>
<Service
class="org.talend.sdk.component.studio.service.TaCoKitDependencyService"
serviceId="ITaCoKitDependencyService">
</Service>
</extension>
<extension
point="org.talend.designer.core.generators">
@@ -308,4 +312,7 @@
<Service serviceId="IGenericWizardService" class="org.talend.sdk.component.studio.metadata.WizardRegistry" />
</extension>
-->
<extension point="org.talend.core.runtime.buildExport_provider">
<dependenciesProvider class="org.talend.sdk.component.studio.provider.TacokitExportDependenciesProvider"></dependenciesProvider>
</extension>
</plugin>

View File

@@ -0,0 +1,171 @@
/*
* Copyright (C) 2006-2020 Talend Inc. - www.talend.com
*
* 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.talend.sdk.component.studio.provider;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static org.talend.sdk.component.studio.util.TaCoKitUtil.findM2Path;
import static org.talend.sdk.component.studio.util.TaCoKitUtil.gavToMvnPath;
import static org.talend.sdk.component.studio.util.TaCoKitUtil.getJobComponents;
import static org.talend.sdk.component.studio.util.TaCoKitUtil.getTaCoKitComponents;
import static org.talend.sdk.component.studio.util.TaCoKitUtil.hasTaCoKitComponents;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.talend.commons.exception.ExceptionHandler;
import org.talend.core.CorePlugin;
import org.talend.core.model.properties.Item;
import org.talend.core.runtime.process.ITalendProcessJavaProject;
import org.talend.core.runtime.repository.build.BuildExportManager;
import org.talend.core.runtime.repository.build.BuildExportManager.EXPORT_TYPE;
import org.talend.core.runtime.repository.build.IBuildExportDependenciesProvider;
import org.talend.repository.documentation.ExportFileResource;
import org.talend.sdk.component.studio.ComponentModel;
import org.talend.sdk.component.studio.util.TaCoKitConst;
public class TacokitExportDependenciesProvider implements IBuildExportDependenciesProvider {
private final static Logger LOG = LoggerFactory.getLogger(TacokitExportDependenciesProvider.class.getName());
/**
* Called when exporting a job, this is up to the implementor to check that the item should export the dependencies.
*
* We use this interface as a hook to feed MAVEN-INF repository.
*
* Side-note: this method is called every time we have an ESB job export as Microservice export also calls it.
*
* @param exportFileResource resources to export, mainly needed in OSGi.
* @param item <code>ProcessItem</code>
*
* @see org.talend.core.runtime.repository.build.IBuildExportDependenciesProvider
*/
@Override
public void exportDependencies(final ExportFileResource exportFileResource, final Item item) {
if (!BuildExportManager.getInstance().getCurrentExportType()
.equals(EXPORT_TYPE.OSGI) || !hasTaCoKitComponents(getJobComponents(item))) {
return;
}
LOG.debug("[exportDependencies] Searching for TaCoKit components...");
final Map<String, String> plugins = new HashMap<String, String>();
getTaCoKitComponents(getJobComponents(item))
.map(ComponentModel::getId)
.forEach(id -> {
plugins.put(id.getPlugin(), gavToMvnPath(id.getPluginLocation()));
});
LOG.info("[exportDependencies] Found {} TaCoKit components.", plugins.size());
try {
ITalendProcessJavaProject project = CorePlugin.getDefault().getRunProcessService()
.getTalendJobJavaProject(item.getProperty());
final String output = project.getResourcesFolder().getLocationURI().getPath();
final Path m2 = findM2Path();
final Path resM2 = Paths.get(output, TaCoKitConst.MAVEN_INF, "repository");
final Path coordinates = Paths.get(output, TaCoKitConst.TALEND_INF, "plugins.properties");
exportFileResource.addResource("TALEND-INF/", coordinates.toUri().toURL());
Files.createDirectories(resM2);
if (Files.exists(coordinates)) {
Files.readAllLines(coordinates).stream()
.filter(line -> !line.matches("^\\s?#"))
.filter(line -> line.matches(".*=.*"))
.map(line -> line.split("="))
// we assume gav already translated
.forEach((line) -> plugins.putIfAbsent(line[0].trim(), line[1].trim()));
} else {
Files.createDirectories(coordinates.getParent());
}
// Feed MAVEN-INF repository
plugins.forEach((plugin, location) -> {
LOG.info("[exportDependencies] Adding {} to MAVEN-INF.", plugin);
final Path src = m2.resolve(location);
final Path dst = resM2.resolve(location);
try {
// First, cp component jar
copyJar(src, dst, exportFileResource);
// then, find deps for current plugin : This is definitely needed for the microservice case and may
// help to avoid classes collisions as it may happen with azure-dls-gen2 for instance!
JarFile jar = new JarFile(src.toFile());
final JarEntry entry = jar.getJarEntry("TALEND-INF/dependencies.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(jar.getInputStream(entry)));
reader.lines()
.filter(l -> !l.endsWith(":test"))
.map(this::translateGavToJar)
.peek(dep -> LOG.debug("[exportDependencies] Copying dependency {} to MAVEN-INF.", dep))
.forEach(dep -> copyJar(m2.resolve(dep), resM2.resolve(dep), exportFileResource));
reader.close();
jar.close();
} catch (IOException | IllegalStateException e) {
LOG.error("[exportDependencies] Error occurred during artifact copy:", e);
ExceptionHandler.process(e);
}
});
// Finalize by writing our plugins.properties
final StringBuffer coord = new StringBuffer("# component-runtime components coordinates:\n");
plugins.forEach((k, v) -> coord.append(String.format("%s = %s\n", k, v)));
Files.copy(new BufferedInputStream(new ByteArrayInputStream(coord.toString()
.getBytes())), coordinates, REPLACE_EXISTING);
// For microservice m2 extraction, not necessary for real OSGi bundle
System.setProperty("talend.component.manager.components.present", "true");
LOG.info("[exportDependencies] Finished MAVEN-INF feeding.");
} catch (Exception e) {
LOG.error("[exportDependencies] Error occurred:", e);
ExceptionHandler.process(e);
}
}
/**
* Class wrapper for {@link @TaCoKitDependencyUtil#gavToJar(String)}
*
* @param gav see {@link @TaCoKitDependencyUtil#gavToJar(String)}
*
* @return a translated maven path
*/
public String translateGavToJar(String gav) {
return gavToMvnPath(gav);
}
/**
* Copy a jar and update export resources.
*
* @param source m2 jar
* @param destination MAVEN-INF destination jar
* @param exportFileResource file resources for job export build
*/
private void copyJar(Path source, Path destination, ExportFileResource exportFileResource) {
try {
if (!Files.exists(destination.getParent())) {
Files.createDirectories(destination.getParent());
}
if (!Files.exists(destination)) {
Files.copy(source, destination);
}
exportFileResource.addResource(destination.getParent().toString()
.substring(destination.getParent().toString().indexOf("MAVEN-INF/")), destination.toUri().toURL());
} catch (IOException e) {
LOG.error("[copyJar] Something went wrong during jar copying...", e);
throw new IllegalStateException(e);
}
}
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright (C) 2006-2020 Talend Inc. - www.talend.com
*
* 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.talend.sdk.component.studio.service;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.talend.core.model.components.IComponent;
import org.talend.core.model.properties.Item;
import org.talend.core.service.ITaCoKitDependencyService;
import org.talend.sdk.component.studio.ComponentModel;
import org.talend.sdk.component.studio.util.TaCoKitUtil;
public class TaCoKitDependencyService implements ITaCoKitDependencyService {
private final static Logger LOG = LoggerFactory.getLogger(TaCoKitDependencyService.class.getName());
public final static List<String> TACOKIT_JARS_BLACKLIST = Arrays.asList("component-api-",
"component-runtime-design-extension-", "component-runtime-di-", "component-runtime-impl-",
"component-runtime-manager-", "component-spi-", "container-core-", "geronimo-annotation_1.3_spec-",
"geronimo-json_1.1_spec-", "geronimo-jsonb_1.0_spec-", "johnzon-core-", "johnzon-jsonb-", "johnzon-mapper-",
"slf4j-api-", "slf4j-log4j12-", "xbean-asm7-shaded-", "xbean-finder-shaded-", "xbean-reflect-");
/**
* @param components
*
* @return
*/
@Override
public Set<String> getTaCoKitOnlyDependencies(final Stream<IComponent> components) {
LOG.debug("[tckOnlyDependencies] Searching for components dependencies...");
final Set<String> diDeps = new HashSet<>();
final Set<String> tckDeps = new HashSet<>();
components.forEach(component -> {
final Set<String> deps = component.getModulesNeeded()
.stream()
.map(d -> Optional.ofNullable(d.getModuleLocaion())
.map(loc -> loc.substring(loc.lastIndexOf("/") + 1))
.orElseGet(() -> d.getModuleName()))
.filter(jar -> TACOKIT_JARS_BLACKLIST.stream().noneMatch(tck -> jar.contains(tck)))
.collect(Collectors.toSet());
if (ComponentModel.class.isInstance(component)) {
tckDeps.addAll(deps);
} else {
diDeps.addAll(deps);
}
});
tckDeps.removeAll(diDeps);
LOG.info("[tckOnlyDependencies] Found {} TaCoKit components only dependencies.", tckDeps.size());
return tckDeps;
}
@Override
public Stream<IComponent> getJobComponents(final Item item) {
return TaCoKitUtil.getJobComponents(item);
}
@Override
public Path findM2Path() {
return TaCoKitUtil.findM2Path();
}
@Override
public boolean hasTaCoKitComponents(final Stream<IComponent> components) {
return TaCoKitUtil.hasTaCoKitComponents(components);
}
}

View File

@@ -65,4 +65,8 @@ public class TaCoKitConst {
public static final String COMPONENT_NAME_PREFIX = "t"; //$NON-NLS-1$
public static final String BASE_HELP_LINK = "org.talend.help."; //$NON-NLS-1$
public static final String MAVEN_INF = "MAVEN-INF"; //$NON-NLS-1$
public static final String TALEND_INF = "TALEND-INF"; //$NON-NLS-1$
}

View File

@@ -13,31 +13,46 @@
package org.talend.sdk.component.studio.util;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.Stack;
import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.common.util.EList;
import org.talend.commons.utils.data.container.Container;
import org.talend.commons.utils.system.EnvironmentUtils;
import org.talend.core.model.components.ComponentCategory;
import org.talend.core.model.components.IComponent;
import org.talend.core.model.general.Project;
import org.talend.core.model.properties.ConnectionItem;
import org.talend.core.model.properties.Item;
import org.talend.core.model.properties.ProcessItem;
import org.talend.core.model.repository.ERepositoryObjectType;
import org.talend.core.model.repository.IRepositoryViewObject;
import org.talend.core.repository.model.ProxyRepositoryFactory;
import org.talend.core.runtime.maven.MavenConstants;
import org.talend.core.ui.component.ComponentsFactoryProvider;
import org.talend.designer.core.model.utils.emf.talendfile.NodeType;
import org.talend.designer.core.utils.UnifiedComponentUtil;
import org.talend.repository.ProjectManager;
import org.talend.sdk.component.server.front.model.ComponentIndex;
import org.talend.sdk.component.server.front.model.ConfigTypeNode;
import org.talend.sdk.component.server.front.model.ConfigTypeNodes;
import org.talend.sdk.component.studio.ComponentModel;
import org.talend.sdk.component.studio.Lookups;
import org.talend.sdk.component.studio.metadata.TaCoKitCache;
import org.talend.sdk.component.studio.metadata.WizardRegistry;
@@ -55,8 +70,10 @@ public class TaCoKitUtil {
* Get ConnectionItem from specified project
*
* @param project {@link Project} only search from the given project
* @param itemId item id
* @param itemId item id
*
* @return stored item of the given parameters, or null
*
* @throws Exception unexpected exception occured during searching
*/
public static ConnectionItem getLatestTaCoKitConnectionItem(final Project project, final String itemId)
@@ -73,7 +90,9 @@ public class TaCoKitUtil {
* Get ConnectionItem from main project or it's reference project
*
* @param itemId item id
*
* @return stored item of the given parameters, or null
*
* @throws Exception unexpected exception occured during searching
*/
public static ConnectionItem getLatestTaCoKitConnectionItem(final String itemId) throws Exception {
@@ -176,7 +195,7 @@ public class TaCoKitUtil {
ERepositoryObjectType eType = ERepositoryObjectType.valueOf(type);
if (eType == null) {
eType = new WizardRegistry().createRepositoryObjectType(type, label, alias, folderPathStr, 1,
new String[] { ERepositoryObjectType.PROD_DI });
new String[]{ ERepositoryObjectType.PROD_DI });
TaCoKitCache taCoKitCache = Lookups.taCoKitCache();
ConfigTypeNode parentTypeNode = taCoKitCache.getConfigTypeNodeMap().get(configTypeNode.getParentId());
if (parentTypeNode == null) {
@@ -223,8 +242,9 @@ public class TaCoKitUtil {
/**
* Method to create component name from component's family name and component's name itself.
*
* @param familyName component's family name
* @param familyName component's family name
* @param componentName component's name
*
* @return full component name
*/
public static String getFullComponentName(final String familyName, final String componentName) {
@@ -317,7 +337,7 @@ public class TaCoKitUtil {
}
private static PropertyNode getSamePropertyNode(Stack<Object> visited, PropertyNode propertyNode,
ConfigTypeNode configTypeNode) {
ConfigTypeNode configTypeNode) {
if (propertyNode == null || visited.contains(propertyNode)) {
return null;
}
@@ -374,12 +394,14 @@ public class TaCoKitUtil {
}
public static int getConfigTypeVersion(final PropertyDefinitionDecorator p, final ConfigTypeNodes configTypeNodes,
final String familyId) {
final String familyId) {
final String type = p.getMetadata().get("configurationtype::type");
final String name = p.getMetadata().get("configurationtype::name");
return configTypeNodes.getNodes().values().stream().filter(c -> c.getConfigurationType() != null && c.getName() != null)
return configTypeNodes.getNodes().values().stream()
.filter(c -> c.getConfigurationType() != null && c.getName() != null)
.filter(c -> c.getConfigurationType().equals(type) && c.getName().equals(name))
.filter(c -> familyId.equals(getPropertyFamilyId(c, configTypeNodes))).findFirst().map(ConfigTypeNode::getVersion)
.filter(c -> familyId.equals(getPropertyFamilyId(c, configTypeNodes))).findFirst()
.map(ConfigTypeNode::getVersion)
.orElse(-1);
}
@@ -394,6 +416,103 @@ public class TaCoKitUtil {
return parent;
}
/**
* Find the maven repository path.
*
* @return the configured m2 repository path
*/
public static java.nio.file.Path findM2Path() {
return Optional.ofNullable(System.getProperty("talend.component.manager.m2.repository"))
.map(Paths::get)
.orElseGet(() -> {
// check if we are in the studio process if so just grab the the studio config
final String m2Repo = System.getProperty("maven.repository");
if (!"global".equals(m2Repo)) {
final String m2StudioRepo = EnvironmentUtils.isWindowsSystem()
? System.getProperty("osgi.configuration.area", "").replaceAll("^file:/", "")
: System.getProperty("osgi.configuration.area", "").replaceAll("^file:", "");
final java.nio.file.Path localM2 = Paths.get(m2StudioRepo, ".m2/repository");
if (Files.exists(localM2)) {
return localM2;
}
}
// defaults to user m2
return Paths.get(System.getProperty("user.home", "")).resolve(".m2/repository");
});
}
/**
* Translates a GAV (ie com.tutorial:tutorial-component:0.0.1) to a maven repository path (ie com/tutorial/tutorial-component/0.0.1/tutorial-component-0.0.1.jar).
*
* @param gav GroupId ArtifactId Version. The GAV may have the following forms:
* com.tutorial:tutorial-component:0.0.1
* or
* com.tutorial:tutorial-component:jar:0.0.1:compile
*
* @return a translated maven path
*/
public static String gavToMvnPath(String gav) {
final String jarPathFmt = "%s/%s/%s/%s-%s.jar";
final String[] segments = gav.split(":");
if (segments.length < 3) {
throw new IllegalArgumentException("Bad GAV given!"); // TODO improve message
}
String group = segments[0].replaceAll("\\.", "/");
String artifact = segments[1];
String version = "";
if (segments.length == 3) {
version = segments[2];
} else {
version = segments[3];
}
return String.format(jarPathFmt, group, artifact, version, artifact, version);
}
/**
* Get all components defined in <code>item</code>.
*
* @param item the currently processed <code>ProcessItem</code> during job build export
*
* @return a non-null stream of {@link IComponent}
*/
public static Stream<IComponent> getJobComponents(final Item item) {
final EList<?> nodes = ProcessItem.class.cast(item).getProcess().getNode();
final String DI = ComponentCategory.CATEGORY_4_DI.getName();
return nodes.stream().map(node -> {
final String componentName = ((NodeType) node).getComponentName();
IComponent component = ComponentsFactoryProvider.getInstance().get(componentName, DI);
if (component == null) {
component = UnifiedComponentUtil.getDelegateComponent(componentName, DI);
}
return component;
}).filter(Objects::nonNull);
}
/**
* Get component-runtime components from <code>components</code>.
*
* @param components <code>{@link IComponent}</code>
*
* @return a non-null stream of {@link ComponentModel}
*/
public static Stream<ComponentModel> getTaCoKitComponents(final Stream<IComponent> components) {
return components
.filter(ComponentModel.class::isInstance)
.map(ComponentModel.class::cast);
}
/**
* Check if <code>components</code> holds component-runtime components.
*
* @param components <code>IComponent</code>
*
* @return true if item has some component-runtime components
*/
public static boolean hasTaCoKitComponents(final Stream<IComponent> components) {
return components.anyMatch(ComponentModel.class::isInstance);
}
public static class GAV {
private String groupId;

View File

@@ -22,9 +22,14 @@ import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Test;
import org.talend.core.model.process.EParameterFieldType;
import org.talend.core.model.process.IElement;
import org.talend.core.model.process.IElementParameter;
import org.talend.core.model.process.INode;
@@ -147,6 +152,15 @@ public class ExpressionTest {
}
}
private ElementParameter createMockParameterWithLineInTable(String paramName, Map<String, Object> line) {
ElementParameter param = mock(ElementParameter.class);
when(param.getFieldType()).thenReturn(EParameterFieldType.TABLE);
when(param.getName()).thenReturn(paramName);
List<Map<String, Object>> list = Stream.of(line).collect(Collectors.toList());
when(param.getValue()).thenReturn(list);
return param;
}
@Test
public void testEvaluateDistrib_simplecase() {
List<IElementParameter> params = new ArrayList<>();
@@ -238,7 +252,19 @@ public class ExpressionTest {
"!DISTRIB[#LINK@NODE.CONNECTION.DISTRIBUTION, #LINK@NODE.CONNECTION.HIVE_VERSION].doSupportUseDatanodeHostname[]",
params, paramNode));
}
@Test
public void testEvaluateContains() {
List<IElementParameter> params = new ArrayList<>();
Map<String, Object> line = new LinkedHashMap<String, Object>() {{
put("ADDITIONAL_ARGUMENT", "'hive.import'");
put("ADDITIONAL_VALUE", "'true'");
}};
ElementParameter param1 = createMockParameterWithLineInTable("ADDITIONAL_JAVA", line);
params.add(param1);
assertTrue(Expression.evaluateContains("ADDITIONAL_JAVA CONTAINS {ADDITIONAL_ARGUMENT='hive.import', ADDITIONAL_VALUE='true'}", params));
}
@Test
public void testIsThereCondition() {
assertTrue(Expression.isThereCondition("a=1 and b=2", "and"));
@@ -255,5 +281,4 @@ public class ExpressionTest {
assertFalse(Expression.isThereCondition("standard='aaa'", "and"));
assertFalse(Expression.isThereCondition("story='aaa'", "or"));
}
}