001/** 002 * Copyright (C) 2006-2025 Talend Inc. - www.talend.com 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.talend.sdk.component.tools; 017 018import static java.util.Optional.ofNullable; 019import static java.util.stream.Collectors.joining; 020 021import java.io.File; 022import java.io.FileOutputStream; 023import java.io.IOException; 024import java.io.OutputStream; 025import java.lang.reflect.Method; 026import java.net.MalformedURLException; 027import java.util.Collection; 028import java.util.Date; 029import java.util.List; 030import java.util.Properties; 031import java.util.stream.Stream; 032 033import org.apache.xbean.finder.AnnotationFinder; 034import org.apache.xbean.finder.archive.Archive; 035import org.apache.xbean.finder.archive.ClasspathArchive; 036import org.apache.xbean.finder.archive.CompositeArchive; 037import org.apache.xbean.finder.filter.ExcludeIncludeFilter; 038import org.apache.xbean.finder.filter.Filter; 039import org.apache.xbean.finder.filter.Filters; 040import org.apache.xbean.finder.filter.IncludeExcludeFilter; 041import org.talend.sdk.component.api.input.Emitter; 042import org.talend.sdk.component.api.input.PartitionMapper; 043import org.talend.sdk.component.api.internationalization.Internationalized; 044import org.talend.sdk.component.api.processor.Processor; 045import org.talend.sdk.component.api.service.Service; 046import org.talend.sdk.component.api.service.http.Request; 047import org.talend.sdk.component.api.standalone.DriverRunner; 048 049import lombok.RequiredArgsConstructor; 050 051@RequiredArgsConstructor 052public class ScanTask implements Runnable { 053 054 private final Collection<File> scannedFiles; 055 056 private final List<String> excludes; 057 058 private final List<String> includes; 059 060 private final String filterStrategy; 061 062 private final File output; 063 064 @Override 065 public void run() { 066 output.getParentFile().mkdirs(); 067 try (final OutputStream stream = new FileOutputStream(output)) { 068 final Properties properties = new Properties(); 069 properties.setProperty("classes.list", scanList().collect(joining(","))); 070 properties.store(stream, "generated by " + getClass() + " at " + new Date()); 071 } catch (final IOException e) { 072 throw new IllegalStateException(e.getMessage(), e); 073 } 074 } 075 076 private Stream<String> scanList() { 077 final AnnotationFinder finder = newFinder(); 078 final Filter filter = newFilter(); 079 return Stream 080 .concat(Stream 081 .of(PartitionMapper.class, Processor.class, Emitter.class, DriverRunner.class, Service.class, 082 Internationalized.class) 083 .flatMap(it -> finder.findAnnotatedClasses(it).stream()), 084 Stream 085 .of(Request.class) 086 .flatMap(it -> finder.findAnnotatedMethods(it).stream()) 087 .map(Method::getDeclaringClass)) 088 .distinct() 089 .map(Class::getName) 090 .sorted() 091 .filter(filter::accept); 092 } 093 094 private Filter newFilter() { 095 final Filter accept = ofNullable(includes) 096 .filter(it -> it.size() > 0) 097 .map(i -> i.toArray(new String[0])) 098 .map(Filters::patterns) 099 .orElseGet(() -> name -> true); 100 final Filter reject = ofNullable(excludes) 101 .filter(it -> it.size() > 0) 102 .map(i -> i.toArray(new String[0])) 103 .map(Filters::patterns) 104 .orElseGet(() -> name -> false); 105 if ("include-exclude".equals(filterStrategy)) { 106 return new IncludeExcludeFilter(accept, reject); 107 } 108 return new ExcludeIncludeFilter(accept, reject); 109 } 110 111 private AnnotationFinder newFinder() { 112 return new AnnotationFinder(new CompositeArchive(scannedFiles.stream().map(c -> { 113 try { 114 return ClasspathArchive.archive(Thread.currentThread().getContextClassLoader(), c.toURI().toURL()); 115 } catch (final MalformedURLException e) { 116 throw new IllegalArgumentException(e); 117 } 118 }).toArray(Archive[]::new))); 119 } 120}