001/** 002 * Copyright (C) 2006-2020 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.server.configuration; 017 018import java.util.List; 019import java.util.Optional; 020 021import javax.annotation.PostConstruct; 022import javax.enterprise.context.ApplicationScoped; 023import javax.enterprise.inject.spi.CDI; 024import javax.inject.Inject; 025 026import org.eclipse.microprofile.config.inject.ConfigProperty; 027import org.talend.sdk.component.api.meta.Documentation; 028 029import lombok.Getter; 030import lombok.extern.slf4j.Slf4j; 031 032@Slf4j 033@Getter 034@ApplicationScoped 035public class ComponentServerConfiguration { 036 037 @Inject 038 @Documentation("If set it will replace any message for exceptions. Set to `false` to use the actual exception message.") 039 @ConfigProperty(name = "talend.component.server.jaxrs.exceptionhandler.defaultMessage", defaultValue = "false") 040 private String defaultExceptionMessage; 041 042 @Inject 043 @Documentation("The local maven repository used to locate components and their dependencies") 044 @ConfigProperty(name = "talend.component.server.maven.repository") 045 private Optional<String> mavenRepository; 046 047 // property to list plugins directly by gav. This is nice to set it on the cli but not as a maintenance solution. 048 @Inject 049 @Documentation("A comma separated list of gav to locate the components") 050 @ConfigProperty(name = "talend.component.server.component.coordinates") 051 private Optional<String> componentCoordinates; 052 053 // property to list plugins like in a fatjar, ie value = gav. Nice for assemblies, less for demo/cli usage. 054 @Inject 055 @Documentation("A property file (or multiple comma separated) where the value is a gav of a component to register" 056 + "(complementary with `coordinates`). Note that the path can end up with `*` or `*.properties` " 057 + "to take into account all properties in a folder.") 058 @ConfigProperty(name = "talend.component.server.component.registry") 059 private Optional<List<String>> componentRegistry; 060 061 @Inject 062 @Documentation("Should the /documentation endpoint be activated. " 063 + "Note that when called on localhost the doc is always available.") 064 @ConfigProperty(name = "talend.component.server.documentation.active", defaultValue = "true") 065 private Boolean supportsDocumentation; 066 067 // sync with org.talend.sdk.component.server.service.security.SecurityExtension.addSecurityHandlers 068 @Inject 069 @Documentation("How to validate a connection. Accepted values: securityNoopHandler.") 070 @ConfigProperty(name = "talend.component.server.security.connection.handler", defaultValue = "securityNoopHandler") 071 private String securityConnectionHandler; 072 073 // sync with org.talend.sdk.component.server.service.security.SecurityExtension.addSecurityHandlers 074 @Inject 075 @Documentation("How to validate a command/request. Accepted values: securityNoopHandler.") 076 @ConfigProperty(name = "talend.component.server.security.command.handler", defaultValue = "securityNoopHandler") 077 private String securityCommandHandler; 078 079 @Inject 080 @Documentation("Should the component extensions add required dependencies.") 081 @ConfigProperty(name = "talend.component.server.component.extend.dependencies", defaultValue = "true") 082 private Boolean addExtensionDependencies; 083 084 @Inject 085 @Documentation("A component translation repository. This is where you put your documentation translations. " 086 + "Their name must follow the pattern `documentation_${container-id}_language.adoc` where `${container-id}` " 087 + "is the component jar name (without the extension and version, generally the artifactId).") 088 @ConfigProperty(name = "talend.component.server.component.documentation.translations", 089 defaultValue = "${home}/documentations") 090 private String documentationI18nTranslations; 091 092 @Inject 093 @Documentation("Should the /api/v1/environment endpoint be activated. " 094 + "It shows some internal versions and git commit which are not always desirable over the wire.") 095 @ConfigProperty(name = "talend.component.server.environment.active", defaultValue = "true") 096 private Boolean supportsEnvironment; 097 098 @Inject 099 @Documentation("Accepted tokens in Authorization header for remote calls to secured endpoints " 100 + "(/api/v1/environment or /documentation).") 101 @ConfigProperty(name = "talend.component.server.filter.secured.tokens", defaultValue = "-") 102 private String securedEndpointsTokens; 103 104 @Inject 105 @Documentation("A folder available for the server - don't forget to mount it in docker if you are using the " 106 + "image - which accepts subfolders named as component plugin id " 107 + "(generally the artifactId or jar name without the version, ex: jdbc). Each family folder can contain:\n\n" 108 + "- a `user-configuration.properties` file which will be merged with component configuration system " 109 + "(see services). This properties file enables the function `userJar(xxxx)` to replace the jar named `xxxx` " 110 + "by its virtual gav (`groupId:artifactId:version`),\n" 111 + "- a list of jars which will be merged with component family classpath\n") 112 @ConfigProperty(name = "talend.component.server.user.extensions.location") 113 private Optional<String> userExtensions; 114 115 @Inject 116 @Documentation("Should the implicit artifacts be provisionned to a m2. If set to `auto` it tries to detect " 117 + "if there is a m2 to provision - recommended, if set to `skip` it is ignored, else it uses the value as a " 118 + "m2 path.") 119 @ConfigProperty(name = "talend.component.server.user.extensions.provisioning.location", defaultValue = "auto") 120 private String userExtensionsAutoM2Provisioning; 121 122 @Inject 123 @Documentation("Timeout for extension initialization at startup, since it ensures the startup wait extensions " 124 + "are ready and loaded it allows to control the latency it implies.") 125 @ConfigProperty(name = "talend.component.server.component.extension.startup.timeout", defaultValue = "180000") 126 private Long extensionsStartupTimeout; 127 128 @Inject 129 @Documentation("If you deploy some extension, where they can create their dependencies if needed.") 130 @ConfigProperty(name = "talend.component.server.component.extension.maven.repository") 131 private Optional<String> extensionMavenRepository; 132 133 @Inject 134 @Documentation("Should the components using a `@GridLayout` support tab translation. " 135 + "Studio does not suppot that feature yet so this is not enabled by default.") 136 @ConfigProperty(name = "talend.component.server.gridlayout.translation.support", defaultValue = "false") 137 private Boolean translateGridLayoutTabNames; 138 139 @Inject 140 @Documentation("Should the all requests/responses be logged (debug purposes - only work when running with CXF).") 141 @ConfigProperty(name = "talend.component.server.request.log", defaultValue = "false") 142 private Boolean logRequests; 143 144 @Inject 145 @Documentation("Maximum items a cache can store, used for index endpoints.") 146 @ConfigProperty(name = "talend.component.server.cache.maxSize", defaultValue = "1000") 147 private Integer maxCacheSize; 148 149 @Inject 150 @Documentation("Should the lastUpdated timestamp value of `/environment` " 151 + "endpoint be updated with server start time.") 152 @ConfigProperty(name = "talend.component.server.lastUpdated.useStartTime", defaultValue = "false") 153 private Boolean changeLastUpdatedAtStartup; 154 155 @Inject 156 @Documentation("These patterns are used to find the icons in the classpath(s).") 157 @ConfigProperty(name = "talend.component.server.icon.paths", 158 defaultValue = "icons/%s.svg,icons/svg/%s.svg,icons/%s_icon32.png,icons/png/%s_icon32.png") 159 private List<String> iconExtensions; 160 161 @Inject 162 @Documentation("For caching reasons the goal is to reduce the locales to the minimum required numbers. " 163 + "For instance we avoid `fr` and `fr_FR` which would lead to the same entries but x2 in terms of memory. " 164 + "This mapping enables that by whitelisting allowed locales, default being `en`. " 165 + "If the key ends with `*` it means all string starting with the prefix will match. " 166 + "For instance `fr*` will match `fr_FR` but also `fr_CA`.") 167 @ConfigProperty(name = "talend.component.server.locale.mapping", defaultValue = "en*=en\nfr*=fr\nzh*=zh_CN\nja*=ja") 168 private String localeMapping; 169 170 @PostConstruct 171 private void init() { 172 if (logRequests != null && logRequests) { 173 final ClassLoader loader = Thread.currentThread().getContextClassLoader(); 174 try { 175 doActivateDebugMode(loader, loader.loadClass("org.apache.cxf.ext.logging.LoggingFeature")); 176 } catch (final Exception | NoClassDefFoundError e) { 177 try { 178 doActivateDebugMode(loader, loader.loadClass("org.apache.cxf.feature.LoggingFeature")); 179 } catch (final Exception | NoClassDefFoundError ex) { 180 log.warn("Can't honor log request configuration, skipping ({})", e.getMessage()); 181 } 182 } 183 } 184 } 185 186 private void doActivateDebugMode(final ClassLoader loader, final Class<?> feature) 187 throws ClassNotFoundException, InstantiationException, IllegalAccessException, 188 java.lang.reflect.InvocationTargetException, NoSuchMethodException { 189 final Class<?> bus = loader.loadClass("org.apache.cxf.Bus"); 190 final Object instance = feature.getConstructor().newInstance(); 191 final Object busInstance = CDI.current().select(bus).get(); 192 feature.getMethod("initialize", bus).invoke(instance, busInstance); 193 log.info("Activated debug mode - will log requests/responses"); 194 } 195}