001/**
002 * Copyright (C) 2006-2022 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.spi.component;
017
018import static java.util.Collections.emptyList;
019import static java.util.Collections.emptyMap;
020
021import java.lang.instrument.ClassFileTransformer;
022import java.util.Collection;
023import java.util.Collections;
024import java.util.Map;
025
026/**
027 * Provide a way to interact with component scanning and metadata extraction.
028 *
029 * Note: it requires to use
030 * org.talend.sdk.component.runtime.manager.ComponentManager to be activated.
031 */
032public interface ComponentExtension {
033
034    /**
035     * @return true if the extension can be used in current environment.
036     */
037    default boolean isActive() {
038        return true;
039    }
040
041    /**
042     * @param context
043     * the component context allowing to interact with the container.
044     */
045    void onComponent(ComponentContext context);
046
047    /**
048     * @param componentType
049     * the expected framework component type (can be Mapper or
050     * Processor).
051     * @return true if convert can be used for that kind of component, false
052     * otherwise.
053     */
054    boolean supports(Class<?> componentType);
055
056    /**
057     * Note: you can assume supports() was called before going into this method.
058     *
059     * @param instance
060     * the instantiated component (native instance).
061     * @param component
062     * the expected framework component type (can be Mapper or
063     * Processor).
064     * @param <T>
065     * the generic matching component parameter.
066     * @return an instance of component.
067     */
068    <T> T convert(ComponentInstance instance, Class<T> component);
069
070    /**
071     * @param plugin the plugin to enrich with services.
072     * @return the services specific to the extension.
073     */
074    default Map<Class<?>, Object> getExtensionServices(final String plugin) {
075        return emptyMap();
076    }
077
078    /**
079     * The priority of the extension.
080     * Extensions are sorted by priority and the first one matching (supports) wins.
081     *
082     * @return the priority for this extension, smaller is the highest priority.
083     */
084    default int priority() {
085        return Integer.MAX_VALUE;
086    }
087
088    /**
089     * Unwrap the current instance to another type. Useful to access advanced features of some extensions.
090     *
091     * @param type the expected type.
092     * @param args optional parameters for the unwrapping.
093     * @param <T> the type to cast the extension to.
094     * @return the unwrapped instance or null if not supported.
095     */
096    default <T> T unwrap(final Class<T> type, final Object... args) {
097        if (type.isInstance(this)) {
098            return type.cast(this);
099        }
100        return null;
101    }
102
103    /**
104     * @return a list of transformer to set on the component classloader.
105     */
106    default Collection<ClassFileTransformer> getTransformers() {
107        return emptyList();
108    }
109
110    /**
111     * @return a Stream of dependencies coordinates
112     */
113    default Collection<String> getAdditionalDependencies() {
114        return Collections.emptyList();
115    }
116
117    /**
118     * This is the handle giving the extension information about the component being
119     * processed and allowing to interact with the container lifecycle.
120     */
121    interface ComponentInstance {
122
123        /**
124         * @return the component native instance.
125         */
126        Object instance();
127
128        /**
129         * @return the plugin identifier of the component.
130         */
131        String plugin();
132
133        /**
134         * @return the family identifier of the component.
135         */
136        String family();
137
138        /**
139         * @return the name identifier of the component.
140         */
141        String name();
142    }
143
144    /**
145     * This is the handle giving the extension information about the component being
146     * processed and allowing to interact with the container lifecycle.
147     */
148    interface ComponentContext {
149
150        /**
151         * @return the class representing the component.
152         */
153        Class<?> getType();
154
155        /**
156         * will prevent the component to be usable with findMapper()/findProcessor() but
157         * will also deactivate the associated validation so you can
158         * use @PartitionMapper and @Processor for another runtime than the framework
159         * default one.
160         */
161        void skipValidation();
162
163        /**
164         * Useful for extensions needing to access metadata from another programming model.
165         * Exposing the extension allows to unwrap it to access it.
166         *
167         * @return null if no extension owns the component, the extension instance otherwise.
168         */
169        ComponentExtension owningExtension();
170    }
171}