001/** 002 * Copyright (C) 2006-2024 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.runtime.manager.service; 017 018import java.io.ObjectStreamException; 019import java.util.Iterator; 020import java.util.Map; 021import java.util.NoSuchElementException; 022import java.util.function.Function; 023 024import org.talend.sdk.component.api.record.Record; 025import org.talend.sdk.component.api.service.source.ProducerFinder; 026import org.talend.sdk.component.runtime.input.Input; 027import org.talend.sdk.component.runtime.input.Mapper; 028import org.talend.sdk.component.runtime.manager.ComponentManager; 029import org.talend.sdk.component.runtime.manager.service.api.ComponentInstantiator; 030import org.talend.sdk.component.runtime.serialization.SerializableService; 031 032import lombok.RequiredArgsConstructor; 033import lombok.extern.slf4j.Slf4j; 034 035@Slf4j 036public class ProducerFinderImpl implements ProducerFinder { 037 038 protected String plugin; 039 040 protected ComponentInstantiator.Builder mapperFinder; 041 042 protected Function<Object, Record> recordConverter; 043 044 @Override 045 public ProducerFinder init(final String plugin, final Object builder, final Function<Object, Record> converter) { 046 this.plugin = plugin; 047 mapperFinder = ComponentInstantiator.Builder.class.cast(builder); 048 recordConverter = converter; 049 return this; 050 } 051 052 @Override 053 public Iterator<Record> find(final String familyName, final String inputName, final int version, 054 final Map<String, String> configuration) { 055 final ComponentInstantiator instantiator = getInstantiator(familyName, inputName); 056 final Mapper mapper = findMapper(instantiator, version, configuration); 057 058 return iterator(mapper.create()); 059 } 060 061 protected ComponentInstantiator getInstantiator(final String familyName, final String inputName) { 062 final ComponentInstantiator.MetaFinder datasetFinder = new ComponentInstantiator.ComponentNameFinder(inputName); 063 final ComponentInstantiator instantiator = 064 this.mapperFinder.build(familyName, datasetFinder, ComponentManager.ComponentType.MAPPER); 065 if (instantiator == null) { 066 log.error("Can't find {} for family {}.", inputName, familyName); 067 throw new IllegalArgumentException( 068 String.format("Can't find %s for family %s.", inputName, familyName)); 069 } 070 return instantiator; 071 } 072 073 protected Mapper findMapper(final ComponentInstantiator instantiator, final int version, 074 final Map<String, String> configuration) { 075 return (Mapper) instantiator.instantiate(configuration, version); 076 } 077 078 protected Iterator<Record> iterator(final Input input) { 079 final Iterator<Object> iteratorObject = new InputIterator(input); 080 081 return new IteratorMap<>(iteratorObject, recordConverter); 082 } 083 084 private Object writeReplace() throws ObjectStreamException { 085 return new SerializableService(plugin, ProducerFinder.class.getName()); 086 } 087 088 static class InputIterator implements Iterator<Object> { 089 090 private final Input input; 091 092 private Object nextObject; 093 094 private boolean init; 095 096 InputIterator(final Input input) { 097 this.input = input; 098 } 099 100 private static Object findNext(final Input input) { 101 return input.next(); 102 } 103 104 @Override 105 public boolean hasNext() { 106 synchronized (input) { 107 if (!init) { 108 init = true; 109 input.start(); 110 nextObject = findNext(input); 111 } 112 if (nextObject == null) { 113 input.stop(); 114 } 115 } 116 return nextObject != null; 117 } 118 119 @Override 120 public Object next() { 121 if (!hasNext()) { 122 throw new NoSuchElementException(); 123 } 124 final Object current = nextObject; 125 nextObject = findNext(input); 126 return current; 127 } 128 } 129 130 @RequiredArgsConstructor 131 static class IteratorMap<T, U> implements Iterator<U> { 132 133 private final Iterator<T> wrappedIterator; 134 135 private final Function<T, U> converter; 136 137 @Override 138 public boolean hasNext() { 139 return this.wrappedIterator.hasNext(); 140 } 141 142 @Override 143 public U next() { 144 final T next = this.wrappedIterator.next(); 145 return this.converter.apply(next); 146 } 147 } 148}