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.runtime.input; 017 018import java.io.ByteArrayInputStream; 019import java.io.IOException; 020import java.io.InvalidObjectException; 021import java.io.ObjectInputStream; 022import java.io.ObjectStreamException; 023import java.io.Serializable; 024import java.lang.reflect.Method; 025 026import javax.json.bind.Jsonb; 027 028import org.talend.sdk.component.api.input.Producer; 029import org.talend.sdk.component.api.service.record.RecordBuilderFactory; 030import org.talend.sdk.component.runtime.base.Delegated; 031import org.talend.sdk.component.runtime.base.LifecycleImpl; 032import org.talend.sdk.component.runtime.record.RecordConverters; 033import org.talend.sdk.component.runtime.serialization.ContainerFinder; 034import org.talend.sdk.component.runtime.serialization.EnhancedObjectInputStream; 035import org.talend.sdk.component.runtime.serialization.LightContainer; 036 037import lombok.AllArgsConstructor; 038 039public class InputImpl extends LifecycleImpl implements Input, Delegated { 040 041 private transient Method next; 042 043 private transient RecordConverters converters; 044 045 private transient RecordConverters.MappingMetaRegistry registry; 046 047 private transient Jsonb jsonb; 048 049 private transient RecordBuilderFactory recordBuilderFactory; 050 051 public InputImpl(final String rootName, final String name, final String plugin, final Serializable instance) { 052 super(instance, rootName, name, plugin); 053 } 054 055 protected InputImpl() { 056 // no-op 057 } 058 059 @Override 060 public Object next() { 061 if (next == null) { 062 init(); 063 } 064 final Object record = readNext(); 065 if (record == null) { 066 return null; 067 } 068 final Class<?> recordClass = record.getClass(); 069 if (recordClass.isPrimitive() || String.class == recordClass) { 070 // mainly for tests, can be dropped while build is green 071 return record; 072 } 073 return converters.toRecord(registry, record, this::jsonb, this::recordBuilderFactory); 074 } 075 076 @Override 077 public Object getDelegate() { 078 return delegate; 079 } 080 081 protected Object readNext() { 082 return doInvoke(this.next); 083 } 084 085 protected void init() { 086 next = findMethods(Producer.class).findFirst().get(); 087 converters = new RecordConverters(); 088 registry = new RecordConverters.MappingMetaRegistry(); 089 } 090 091 private Jsonb jsonb() { 092 if (jsonb != null) { 093 return jsonb; 094 } 095 synchronized (this) { 096 if (jsonb == null) { 097 final LightContainer container = ContainerFinder.Instance.get().find(plugin()); 098 jsonb = container.findService(Jsonb.class); 099 } 100 } 101 return jsonb; 102 } 103 104 private RecordBuilderFactory recordBuilderFactory() { 105 if (recordBuilderFactory != null) { 106 return recordBuilderFactory; 107 } 108 synchronized (this) { 109 if (recordBuilderFactory == null) { 110 final LightContainer container = ContainerFinder.Instance.get().find(plugin()); 111 recordBuilderFactory = container.findService(RecordBuilderFactory.class); 112 } 113 } 114 return recordBuilderFactory; 115 } 116 117 protected Object writeReplace() throws ObjectStreamException { 118 return new SerializationReplacer(plugin(), rootName(), name(), serializeDelegate()); 119 } 120 121 @AllArgsConstructor 122 protected static class SerializationReplacer implements Serializable { 123 124 protected String plugin; 125 126 protected String component; 127 128 protected String name; 129 130 protected byte[] value; 131 132 protected Object readResolve() throws ObjectStreamException { 133 try { 134 return new InputImpl(component, name, plugin, loadDelegate()); 135 } catch (final IOException | ClassNotFoundException e) { 136 final InvalidObjectException invalidObjectException = new InvalidObjectException(e.getMessage()); 137 invalidObjectException.initCause(e); 138 throw invalidObjectException; 139 } 140 } 141 142 protected Serializable loadDelegate() throws IOException, ClassNotFoundException { 143 try (final ObjectInputStream ois = new EnhancedObjectInputStream(new ByteArrayInputStream(value), 144 ContainerFinder.Instance.get().find(plugin).classloader())) { 145 return Serializable.class.cast(ois.readObject()); 146 } 147 } 148 } 149}