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 static java.util.Collections.singletonList;
019
020import java.io.ByteArrayInputStream;
021import java.io.ByteArrayOutputStream;
022import java.io.IOException;
023import java.io.InvalidObjectException;
024import java.io.ObjectInputStream;
025import java.io.ObjectOutputStream;
026import java.io.ObjectStreamException;
027import java.io.Serializable;
028import java.util.ArrayList;
029import java.util.List;
030
031import org.talend.sdk.component.runtime.base.Delegated;
032import org.talend.sdk.component.runtime.base.Named;
033import org.talend.sdk.component.runtime.serialization.ContainerFinder;
034import org.talend.sdk.component.runtime.serialization.EnhancedObjectInputStream;
035
036import lombok.AllArgsConstructor;
037
038public class LocalPartitionMapper extends Named implements Mapper, Delegated {
039
040    private Serializable input;
041
042    protected LocalPartitionMapper() {
043        // no-op
044    }
045
046    public LocalPartitionMapper(final String rootName, final String name, final String plugin,
047            final Serializable instance) {
048        super(rootName, name, plugin);
049        this.input = instance;
050    }
051
052    @Override
053    public long assess() {
054        return 1;
055    }
056
057    @Override
058    public List<Mapper> split(final long desiredSize) {
059        return new ArrayList<>(singletonList(this));
060    }
061
062    @Override
063    public Input create() {
064        return Input.class.isInstance(input) ? Input.class.cast(input)
065                : new InputImpl(rootName(), name(), plugin(), input);
066    }
067
068    @Override
069    public boolean isStream() {
070        return false;
071    }
072
073    @Override
074    public void start() {
075        // no-op
076    }
077
078    @Override
079    public void stop() {
080        // no-op
081    }
082
083    @Override
084    public Object getDelegate() {
085        return input;
086    }
087
088    Object writeReplace() throws ObjectStreamException {
089        final Thread thread = Thread.currentThread();
090        final ClassLoader old = thread.getContextClassLoader();
091        thread.setContextClassLoader(input.getClass().getClassLoader());
092        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
093        try (final ObjectOutputStream oos = new ObjectOutputStream(baos)) {
094            oos.writeObject(input);
095        } catch (final IOException e) {
096            throw new IllegalStateException(e);
097        } finally {
098            thread.setContextClassLoader(old);
099        }
100        return new SerializationReplacer(plugin(), rootName(), name(), baos.toByteArray());
101    }
102
103    @AllArgsConstructor
104    private static class SerializationReplacer implements Serializable {
105
106        private final String plugin;
107
108        private final String component;
109
110        private final String name;
111
112        private final byte[] input;
113
114        Object readResolve() throws ObjectStreamException {
115            try {
116                return new LocalPartitionMapper(component, name, plugin, loadDelegate());
117            } catch (final IOException | ClassNotFoundException e) {
118                final InvalidObjectException invalidObjectException = new InvalidObjectException(e.getMessage());
119                invalidObjectException.initCause(e);
120                throw invalidObjectException;
121            }
122        }
123
124        private Serializable loadDelegate() throws IOException, ClassNotFoundException {
125            try (final ObjectInputStream ois = new EnhancedObjectInputStream(new ByteArrayInputStream(input),
126                    ContainerFinder.Instance.get().find(plugin).classloader())) {
127                return Serializable.class.cast(ois.readObject());
128            }
129        }
130    }
131}