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.manager; 017 018import static java.util.Arrays.asList; 019import static java.util.Optional.empty; 020import static java.util.Optional.of; 021 022import java.util.ArrayList; 023import java.util.Collection; 024import java.util.List; 025import java.util.Locale; 026import java.util.Map; 027import java.util.MissingResourceException; 028import java.util.Objects; 029import java.util.Optional; 030import java.util.ResourceBundle; 031import java.util.concurrent.ConcurrentHashMap; 032import java.util.concurrent.ConcurrentMap; 033import java.util.stream.Stream; 034 035import org.talend.sdk.component.runtime.internationalization.ParameterBundle; 036 037import lombok.Data; 038import lombok.ToString; 039import lombok.extern.slf4j.Slf4j; 040 041@Data 042@Slf4j 043@ToString(of = { "path", "name", "type", "metadata" }) 044public class ParameterMeta { 045 046 private static final ParameterBundle NO_PARAMETER_BUNDLE = new ParameterBundle(null, null) { 047 048 @Override 049 protected Optional<String> readValue(final String key) { 050 return empty(); 051 } 052 053 @Override 054 protected Optional<String> readRawValue(final String key) { 055 return empty(); 056 } 057 058 @Override 059 public Optional<String> displayName(final ParameterBundle parent) { 060 return empty(); 061 } 062 063 @Override 064 public Optional<String> placeholder(final ParameterBundle parent) { 065 return empty(); 066 } 067 }; 068 069 private final Source source; 070 071 private final java.lang.reflect.Type javaType; 072 073 private final Type type; 074 075 private final String path; 076 077 private final String name; 078 079 private final String[] i18nPackages; // fallback when the type is not sufficient (java.* types) 080 081 private final List<ParameterMeta> nestedParameters; 082 083 private final Collection<String> proposals; 084 085 private final Map<String, String> metadata; 086 087 private final boolean logMissingResourceBundle; 088 089 private final ConcurrentMap<Locale, ParameterBundle> bundles = new ConcurrentHashMap<>(); 090 091 public ParameterBundle findBundle(final ClassLoader loader, final Locale locale) { 092 final Class<?> type = of(javaType) 093 .filter(Class.class::isInstance) 094 .map(Class.class::cast) 095 .filter(c -> !c.getName().startsWith("java.") && !c.isPrimitive()) 096 .orElse(null); 097 return bundles.computeIfAbsent(locale, l -> { 098 try { 099 final ResourceBundle[] bundles = 100 (i18nPackages != null ? Stream.of(i18nPackages) : Stream.<String> empty()) 101 .filter(Objects::nonNull) 102 .filter(s -> !s.isEmpty()) 103 .distinct() 104 .map(p -> p + "." + "Messages") 105 .map(n -> { 106 try { 107 return ResourceBundle.getBundle(n, locale, loader); 108 } catch (final MissingResourceException mre) { 109 return null; 110 } 111 }) 112 .filter(Objects::nonNull) 113 .toArray(ResourceBundle[]::new); 114 if (bundles.length == 0) { 115 if (logMissingResourceBundle) { 116 log.warn(noBundleMessage()); 117 } 118 return NO_PARAMETER_BUNDLE; 119 } 120 121 final Collection<String> fallbacks = new ArrayList<>(2); 122 final Class<?> declaringClass = source == null ? null : source.declaringClass(); 123 if (declaringClass != null && !declaringClass.getName().startsWith("java")) { 124 final String sourceName = source.name(); 125 fallbacks.add(declaringClass.getName() + '.' + sourceName); 126 if (declaringClass.getEnclosingClass() != null) { 127 fallbacks 128 .add(declaringClass.getEnclosingClass().getSimpleName() + '$' 129 + declaringClass.getSimpleName() + '.' + sourceName); 130 } 131 fallbacks.add(declaringClass.getSimpleName() + '.' + sourceName); 132 } 133 if (type != null) { 134 fallbacks.add(type.getName() + '.' + name); 135 if (type.getEnclosingClass() != null) { 136 fallbacks 137 .add(type.getEnclosingClass().getSimpleName() + '$' + type.getSimpleName() + '.' 138 + name); 139 } 140 fallbacks.add(type.getSimpleName() + '.' + name); 141 } 142 return new ParameterBundle(bundles, path + '.', fallbacks.toArray(new String[fallbacks.size()])); 143 } catch (final MissingResourceException mre) { 144 if (logMissingResourceBundle) { 145 log.warn(noBundleMessage()); 146 } 147 log.debug(mre.getMessage(), mre); 148 return NO_PARAMETER_BUNDLE; 149 } 150 }); 151 } 152 153 private String noBundleMessage() { 154 return (i18nPackages == null ? "No bundle " : "No bundle in " + asList(i18nPackages)) + " (" + path 155 + "), means the display names will be the technical names"; 156 } 157 158 public enum Type { 159 OBJECT, 160 ARRAY, 161 BOOLEAN, 162 STRING, 163 NUMBER, 164 ENUM 165 } 166 167 public interface Source { 168 169 String name(); 170 171 Class<?> declaringClass(); 172 } 173}