Search in sources :

Example 1 with SettingKey

use of org.exist.config.annotation.ConfigurationFieldSettings.SettingKey in project exist by eXist-db.

the class Configurator method configureByCurrent.

private static Configuration configureByCurrent(final Configurable instance, final Configuration configuration) throws ConfigurationException {
    final AFields annotatedFields = getConfigurationAnnotatedFields(instance.getClass());
    final Set<String> properties = configuration.getProperties();
    if (properties.isEmpty()) {
        return configuration;
    }
    // process simple types: String, int, long, boolean
    for (final String property : properties) {
        final AField annotatedField = annotatedFields.findByAnnotationValue(property);
        if (annotatedField == null) {
            LOG.warn("Unused property {} @{}", property, configuration.getName());
            continue;
        }
        final Field field = annotatedField.getField();
        field.setAccessible(true);
        Object value = null;
        final Class<?> fieldType = field.getType();
        try {
            final NewClass newClass = getAnnotation(field, NewClass.class);
            if (newClass != null) {
                value = org.exist.config.mapper.Constructor.load(newClass, instance, configuration.getConfiguration(property));
            } else if (String.class == fieldType) {
                // String
                value = configuration.getProperty(property);
            } else if (int.class == fieldType || Integer.class == fieldType) {
                if (field.isAnnotationPresent(ConfigurationFieldSettings.class)) {
                    final String settings = field.getAnnotation(ConfigurationFieldSettings.class).value();
                    final SettingKey settingKey = SettingKey.forSettings(settings);
                    try {
                        if (settingKey == SettingKey.RADIX) {
                            final int radix = Integer.parseInt(settingKey.extractValueFromSettings(settings));
                            value = Integer.valueOf(configuration.getProperty(property), radix);
                        } else if (settingKey == SettingKey.OCTAL_STRING) {
                            value = Integer.valueOf(configuration.getProperty(property), 8);
                        } else {
                            value = Integer.valueOf(configuration.getProperty(property));
                        }
                    } catch (final NumberFormatException e) {
                        LOG.error(e.getMessage(), e);
                        // ignore
                        continue;
                    }
                } else {
                    value = configuration.getPropertyInteger(property);
                }
            } else if (long.class == fieldType || Long.class == fieldType) {
                // long or Long
                value = configuration.getPropertyLong(property);
            } else if (boolean.class == fieldType || Boolean.class == fieldType) {
                // boolean or Boolean
                value = configuration.getPropertyBoolean(property);
            } else if (Map.class == fieldType) {
                // Map
                // skip contents, they will be processed as structure in the next loop on ConfigurationFieldAsElement
                value = configuration.getPropertyMap(property);
            } else if (List.class == fieldType) {
            // List
            // skip, will be processed as structure in the next loop on ConfigurationFieldAsElement
            // TODO what about simple generic types?
            } else if (XmldbURI.class == fieldType) {
                // use annotation ConfigurationFieldClassMask
                value = org.exist.xmldb.XmldbURI.create(configuration.getProperty(property));
            } else {
                Configuration conf = configuration.getConfiguration(property);
                if (conf == null) {
                    conf = configuration;
                }
                value = create(conf, instance, fieldType);
                if (value == null) {
                    value = configuration.getProperty(property);
                }
            }
            if (value != null && !value.equals(field.get(instance))) {
                Method method = searchForSetMethod(instance.getClass(), field);
                if (method != null) {
                    try {
                        method.invoke(instance, value);
                    } catch (final InvocationTargetException e) {
                        LOG.warn(e);
                        method = null;
                    }
                }
                if (method == null) {
                    field.set(instance, value);
                }
            }
        } catch (final IllegalArgumentException iae) {
            final String msg = "Configuration error: " + EOL + " config: " + configuration.getName() + EOL + " property: " + property + EOL + " message: " + iae.getMessage();
            LOG.error(msg, iae);
            throw new ConfigurationException(msg, iae);
        // return null; //XXX: throw configuration error
        } catch (final IllegalAccessException iae) {
            final String msg = "Security error: " + EOL + " config: " + configuration.getName() + EOL + " property: " + property + EOL + " message: " + iae.getMessage();
            LOG.error(msg, iae);
            throw new ConfigurationException(msg, iae);
        // LOG.error("Security error: " + iae.getMessage(), iae);
        // return null; //XXX: throw configuration error
        }
    }
    // process simple structures: List
    Field field = null;
    try {
        for (final AField<ConfigurationFieldAsElement> element : annotatedFields.getElements()) {
            field = element.getField();
            final Class<?> fieldType = field.getType();
            if (List.class == fieldType) {
                // List
                final String confName = element.getAnnotation().value();
                field.setAccessible(true);
                List list = (List) field.get(instance);
                final Optional<String> referenceBy;
                List<Configuration> confs;
                if (field.isAnnotationPresent(ConfigurationReferenceBy.class)) {
                    confs = configuration.getConfigurations(confName);
                    referenceBy = Optional.ofNullable(field.getAnnotation(ConfigurationReferenceBy.class).value());
                } else {
                    confs = configuration.getConfigurations(confName);
                    referenceBy = Optional.empty();
                }
                if (list == null) {
                    // has to be raw type as we don't know what it should be.
                    list = new ArrayList(confs.size());
                    field.set(instance, list);
                }
                if (confs != null) {
                    // remove & update
                    // referencedBy -> index
                    final Map<String, Integer> removed = new HashMap<>();
                    for (int i = 0; i < list.size(); i++) {
                        final Object obj = list.get(i);
                        Configuration current_conf = null;
                        if (!(obj instanceof Configurable)) {
                            // TODO Surely we should log a problem here or throw an exception?
                            list.remove(i);
                            continue;
                        } else if (obj instanceof Reference) {
                            if (!referenceBy.isPresent()) {
                                LOG.error("illegal design '{}' [{}]", configuration.getName(), field);
                                list.remove(i);
                                continue;
                            } else {
                                final String name = ((Reference) obj).getName();
                                // Lookup for new configuration, update if found
                                final List<Configuration> applicableConfs = filter(confs, conf -> Optional.ofNullable(conf.getPropertyBoolean(referenceBy.get())).map(value -> !value.equals(name)).orElse(true));
                                if (applicableConfs.size() == confs.size()) {
                                    LOG.debug("Configuration was removed, will attempt to replace object [{}].", obj);
                                    final Field referee = getFieldRecursive(Optional.of(list.get(i).getClass()), referenceBy.get());
                                    if (referee != null) {
                                        referee.setAccessible(true);
                                        removed.put((String) referee.get(list.remove(i)), i);
                                    } else {
                                        LOG.error("Could not lookup referenced field: {} against: {}", referenceBy.get(), list.get(i).getClass().getName());
                                        list.remove(i);
                                    }
                                } else {
                                    confs = applicableConfs;
                                }
                            }
                        } else {
                            current_conf = ((Configurable) obj).getConfiguration();
                        }
                        if (current_conf == null) {
                            // skip internal stuff //TODO: static list
                            if (obj instanceof org.exist.security.internal.RealmImpl) {
                                continue;
                            }
                            if (list.size() > i) {
                                if (LOG.isDebugEnabled()) {
                                    LOG.debug("No configured instance of [{}], will attempt to replace object...", obj);
                                }
                                final Field referee = getFieldRecursive(Optional.of(list.get(i).getClass()), referenceBy.get());
                                if (referee != null) {
                                    referee.setAccessible(true);
                                    removed.put((String) referee.get(list.remove(i)), i);
                                } else {
                                    LOG.error("Could not lookup referenced field: {} against: {}", referenceBy.get(), list.get(i).getClass().getName());
                                    list.remove(i);
                                }
                            }
                            continue;
                        }
                        // Lookup for new configuration, update if found
                        final Configuration final_current_conf = current_conf;
                        final List<Configuration> applicableConfs = filter(confs, conf -> !final_current_conf.equals(conf, referenceBy));
                        if (applicableConfs.size() == confs.size()) {
                            LOG.debug("Configuration was removed, will attempt to replace [{}].", obj);
                            if (list.size() > i) {
                                Configurable old = ((Configurable) list.remove(i));
                                String key = old.getConfiguration().getProperty(referenceBy.orElse(Configuration.ID));
                                if (key != null) {
                                    removed.put(key, i);
                                }
                            }
                        } else {
                            confs = applicableConfs;
                        }
                    }
                    // create
                    for (final Configuration conf : confs) {
                        if (referenceBy.isPresent()) {
                            final String value = conf.getProperty(referenceBy.get());
                            if (value != null) {
                                final Optional<ConsumerE<String, ReflectiveOperationException>> updateFn = updateListFn(instance, confName, removed, value);
                                if (!updateFn.isPresent()) {
                                    LOG.error("Could not insert configured object");
                                } else {
                                    try {
                                        updateFn.get().accept(value);
                                        continue;
                                    } catch (final ReflectiveOperationException e) {
                                        LOG.warn("Could not update {} for configuration '{}' referenceBy '{}' for value '{}'", instance.getClass().getName(), conf.getName(), referenceBy.get(), value, e);
                                    }
                                }
                            }
                        } else {
                            final Type genericType = field.getGenericType();
                            if (genericType != null) {
                                if ("java.util.List<java.lang.String>".equals(genericType.toString())) {
                                    final String value = conf.getValue();
                                    if (value != null) {
                                        final Optional<ConsumerE<String, ReflectiveOperationException>> updateFn = updateListFn(instance, confName, removed, value);
                                        if (!updateFn.isPresent()) {
                                            LOG.error("Could not insert configured object");
                                        } else {
                                            try {
                                                updateFn.get().accept(value);
                                                continue;
                                            } catch (final ReflectiveOperationException e) {
                                                LOG.warn("Could not update {} for configuration '{}' for value '{}'", instance.getClass().getName(), conf.getName(), value, e);
                                            }
                                        }
                                    }
                                }
                            }
                        // TODO: AddMethod with Configuration argument
                        }
                        final ConfigurationFieldClassMask annotation = getAnnotation(field, ConfigurationFieldClassMask.class);
                        if (annotation == null) {
                            final NewClass newClass = getAnnotation(field, NewClass.class);
                            if (newClass != null) {
                                final Object obj = org.exist.config.mapper.Constructor.load(newClass, instance, conf);
                                if (obj != null) {
                                    list.add(obj);
                                }
                            } else {
                                LOG.error("Field '{}' must have '@org.exist.config.annotation.ConfigurationFieldClassMask' annotation [{}], skipping instance creation.", field.getName(), conf.getName());
                            }
                            continue;
                        }
                        final String id = conf.getProperty(Configuration.ID);
                        Object[] objs;
                        if (id == null) {
                            objs = new Object[] { "", "" };
                        } else {
                            objs = new Object[] { id.toLowerCase(), id };
                        }
                        final String clazzName = String.format(annotation.value(), objs);
                        final Configurable obj = create(conf, instance, clazzName);
                        if (obj != null) {
                            list.add(obj);
                        }
                    }
                }
            }
        }
    } catch (final IllegalArgumentException iae) {
        final String msg = "Configuration error: " + EOL + " config: " + configuration.getName() + EOL + " field: " + field + EOL + " message: " + iae.getMessage();
        LOG.error(msg, iae);
        throw new ConfigurationException(msg, iae);
    // LOG.error(iae.getMessage(), iae);
    // return null;
    } catch (final IllegalAccessException iae) {
        final String msg = "Security error: " + EOL + " config: " + configuration.getName() + EOL + " field: " + field + EOL + " message: " + iae.getMessage();
        LOG.error(msg, iae);
        throw new ConfigurationException(msg, iae);
    // LOG.error(iae.getMessage(), iae);
    // return null;
    }
    return configuration;
}
Also used : LambdaMetafactory(java.lang.invoke.LambdaMetafactory) Txn(org.exist.storage.txn.Txn) BrokerPool(org.exist.storage.BrokerPool) BiFunction(java.util.function.BiFunction) StringInputSource(org.exist.util.StringInputSource) org.exist.security(org.exist.security) Namespaces(org.exist.Namespaces) SettingKey(org.exist.config.annotation.ConfigurationFieldSettings.SettingKey) LockException(org.exist.util.LockException) SAXParser(javax.xml.parsers.SAXParser) Collection(org.exist.collections.Collection) LifeCycle(org.exist.LifeCycle) Method(java.lang.reflect.Method) Predicate(java.util.function.Predicate) MethodHandles(java.lang.invoke.MethodHandles) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Collectors(java.util.stream.Collectors) InvocationTargetException(java.lang.reflect.InvocationTargetException) SecurityManager(org.exist.security.SecurityManager) Stream(java.util.stream.Stream) Logger(org.apache.logging.log4j.Logger) Type(java.lang.reflect.Type) SAXException(org.xml.sax.SAXException) Annotation(java.lang.annotation.Annotation) Entry(java.util.Map.Entry) FullXmldbURI(org.exist.xmldb.FullXmldbURI) SAXAdapter(org.exist.dom.memtree.SAXAdapter) MethodHandle(java.lang.invoke.MethodHandle) java.util(java.util) SAXSerializer(org.exist.util.serializer.SAXSerializer) QName(org.exist.dom.QName) SAXParserFactory(javax.xml.parsers.SAXParserFactory) Function(java.util.function.Function) MimeType(org.exist.util.MimeType) ConcurrentMap(java.util.concurrent.ConcurrentMap) XMLReader(org.xml.sax.XMLReader) UnsynchronizedByteArrayOutputStream(org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream) XmldbURI(org.exist.xmldb.XmldbURI) DocumentImpl(org.exist.dom.persistent.DocumentImpl) FEATURE_SECURE_PROCESSING(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING) EXistException(org.exist.EXistException) WeakReference(java.lang.ref.WeakReference) XMLConstants(javax.xml.XMLConstants) MethodType.methodType(java.lang.invoke.MethodType.methodType) InputSource(org.xml.sax.InputSource) Database(org.exist.Database) Sync(org.exist.storage.sync.Sync) ExistSAXParserFactory(org.exist.util.ExistSAXParserFactory) Field(java.lang.reflect.Field) org.exist.config.annotation(org.exist.config.annotation) TransactionManager(org.exist.storage.txn.TransactionManager) Element(org.w3c.dom.Element) java.io(java.io) ParameterizedType(java.lang.reflect.ParameterizedType) ConcurrentSkipListSet(java.util.concurrent.ConcurrentSkipListSet) ParserConfigurationException(javax.xml.parsers.ParserConfigurationException) DBBroker(org.exist.storage.DBBroker) ConsumerE(com.evolvedbinary.j8fu.function.ConsumerE) LogManager(org.apache.logging.log4j.LogManager) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Field(java.lang.reflect.Field) org.exist.security(org.exist.security) ParserConfigurationException(javax.xml.parsers.ParserConfigurationException) SettingKey(org.exist.config.annotation.ConfigurationFieldSettings.SettingKey) FullXmldbURI(org.exist.xmldb.FullXmldbURI) XmldbURI(org.exist.xmldb.XmldbURI) WeakReference(java.lang.ref.WeakReference) Method(java.lang.reflect.Method) InvocationTargetException(java.lang.reflect.InvocationTargetException) Type(java.lang.reflect.Type) MimeType(org.exist.util.MimeType) MethodType.methodType(java.lang.invoke.MethodType.methodType) ParameterizedType(java.lang.reflect.ParameterizedType) ConsumerE(com.evolvedbinary.j8fu.function.ConsumerE) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ConcurrentMap(java.util.concurrent.ConcurrentMap)

Aggregations

ConsumerE (com.evolvedbinary.j8fu.function.ConsumerE)1 java.io (java.io)1 Annotation (java.lang.annotation.Annotation)1 LambdaMetafactory (java.lang.invoke.LambdaMetafactory)1 MethodHandle (java.lang.invoke.MethodHandle)1 MethodHandles (java.lang.invoke.MethodHandles)1 MethodType.methodType (java.lang.invoke.MethodType.methodType)1 WeakReference (java.lang.ref.WeakReference)1 Field (java.lang.reflect.Field)1 InvocationTargetException (java.lang.reflect.InvocationTargetException)1 Method (java.lang.reflect.Method)1 ParameterizedType (java.lang.reflect.ParameterizedType)1 Type (java.lang.reflect.Type)1 java.util (java.util)1 Entry (java.util.Map.Entry)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1 ConcurrentMap (java.util.concurrent.ConcurrentMap)1 ConcurrentSkipListSet (java.util.concurrent.ConcurrentSkipListSet)1 BiFunction (java.util.function.BiFunction)1 Function (java.util.function.Function)1