mirror of
https://github.com/ethauvin/rife2.git
synced 2025-05-01 11:08:11 -07:00
Added support for hierarchical properties and field injection for properties.
This commit is contained in:
parent
eb872bdf4c
commit
426104ff0b
25 changed files with 2005 additions and 18 deletions
|
@ -9,6 +9,7 @@ import rife.continuations.ContinuationConfigRuntime;
|
||||||
import rife.continuations.ContinuationContext;
|
import rife.continuations.ContinuationContext;
|
||||||
import rife.continuations.exceptions.*;
|
import rife.continuations.exceptions.*;
|
||||||
import rife.engine.exceptions.*;
|
import rife.engine.exceptions.*;
|
||||||
|
import rife.ioc.HierarchicalProperties;
|
||||||
import rife.template.Template;
|
import rife.template.Template;
|
||||||
import rife.template.TemplateFactory;
|
import rife.template.TemplateFactory;
|
||||||
import rife.template.exceptions.TemplateException;
|
import rife.template.exceptions.TemplateException;
|
||||||
|
@ -204,6 +205,64 @@ public class Context {
|
||||||
return routeMatch_.route();
|
return routeMatch_.route();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Router router() {
|
||||||
|
var route = route();
|
||||||
|
if (route == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return route.router();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HierarchicalProperties properties() {
|
||||||
|
var router = router();
|
||||||
|
if (router == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return router.properties();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a property from this context's {@code HierarchicalProperties}.
|
||||||
|
*
|
||||||
|
* @return the requested property; or {@code null} if it doesn't exist
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public Object property(String name) {
|
||||||
|
var properties = properties();
|
||||||
|
if (null == properties) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return properties.getValue(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for the existence of a property in this context's {@code HierarchicalProperties}.
|
||||||
|
*
|
||||||
|
* @return {@code true} if the property exists; or {@code false} otherwise
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public boolean hasProperty(String name) {
|
||||||
|
var properties = properties();
|
||||||
|
if (null == properties) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return properties.contains(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a collection of the names in this context's {@code HierarchicalProperties}.
|
||||||
|
*
|
||||||
|
* @return the requested collection of names
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public Collection<String> propertyNames() {
|
||||||
|
var properties = properties();
|
||||||
|
if (null == properties) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return properties.getNames();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pauses the execution of the element and creates a new continuation.
|
* Pauses the execution of the element and creates a new continuation.
|
||||||
* <p>The next request will resume exactly at the same location with a
|
* <p>The next request will resume exactly at the same location with a
|
||||||
|
|
|
@ -6,15 +6,13 @@ package rife.engine;
|
||||||
|
|
||||||
import rife.Version;
|
import rife.Version;
|
||||||
import rife.config.RifeConfig;
|
import rife.config.RifeConfig;
|
||||||
import rife.continuations.*;
|
|
||||||
import rife.continuations.exceptions.PauseException;
|
|
||||||
import rife.engine.exceptions.DeferException;
|
import rife.engine.exceptions.DeferException;
|
||||||
import rife.engine.exceptions.RedirectException;
|
import rife.engine.exceptions.RedirectException;
|
||||||
|
import rife.ioc.HierarchicalProperties;
|
||||||
import rife.template.TemplateFactory;
|
import rife.template.TemplateFactory;
|
||||||
import rife.tools.ExceptionFormattingUtils;
|
import rife.tools.ExceptionFormattingUtils;
|
||||||
import rife.tools.ExceptionUtils;
|
import rife.tools.ExceptionUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,6 +23,7 @@ import java.util.logging.Logger;
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
public class Gate {
|
public class Gate {
|
||||||
|
private HierarchicalProperties properties_ = null;
|
||||||
private Site site_ = null;
|
private Site site_ = null;
|
||||||
private Throwable initException_ = null;
|
private Throwable initException_ = null;
|
||||||
|
|
||||||
|
@ -34,7 +33,10 @@ public class Gate {
|
||||||
* @param site the site that will handle the requests
|
* @param site the site that will handle the requests
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
public void setup(Site site) {
|
public void setup(HierarchicalProperties properties, Site site) {
|
||||||
|
var system_properties = new HierarchicalProperties().putAll(System.getProperties());
|
||||||
|
properties_ = properties.parent(system_properties);
|
||||||
|
site.properties_.setParent(properties_);
|
||||||
site_ = site;
|
site_ = site;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -101,12 +101,13 @@ public class RouteClass implements Route {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field.isAnnotationPresent(ActiveSite.class) ||
|
if (field.isAnnotationPresent(ActiveSite.class) ||
|
||||||
field.isAnnotationPresent(Parameter.class) ||
|
|
||||||
field.isAnnotationPresent(Header.class) ||
|
|
||||||
field.isAnnotationPresent(Body.class) ||
|
field.isAnnotationPresent(Body.class) ||
|
||||||
field.isAnnotationPresent(PathInfo.class) ||
|
|
||||||
field.isAnnotationPresent(FileUpload.class) ||
|
|
||||||
field.isAnnotationPresent(Cookie.class) ||
|
field.isAnnotationPresent(Cookie.class) ||
|
||||||
|
field.isAnnotationPresent(FileUpload.class) ||
|
||||||
|
field.isAnnotationPresent(Header.class) ||
|
||||||
|
field.isAnnotationPresent(Parameter.class) ||
|
||||||
|
field.isAnnotationPresent(PathInfo.class) ||
|
||||||
|
field.isAnnotationPresent(Property.class) ||
|
||||||
field.isAnnotationPresent(RequestAttribute.class) ||
|
field.isAnnotationPresent(RequestAttribute.class) ||
|
||||||
field.isAnnotationPresent(SessionAttribute.class)) {
|
field.isAnnotationPresent(SessionAttribute.class)) {
|
||||||
fields.add(field);
|
fields.add(field);
|
||||||
|
@ -227,6 +228,22 @@ public class RouteClass implements Route {
|
||||||
}
|
}
|
||||||
field.set(element, value);
|
field.set(element, value);
|
||||||
}
|
}
|
||||||
|
} else if (field.isAnnotationPresent(Property.class)) {
|
||||||
|
var properties = context.properties();
|
||||||
|
var annotation_name = field.getAnnotation(Property.class).value();
|
||||||
|
if (annotation_name != null && !annotation_name.isEmpty()) {
|
||||||
|
name = annotation_name;
|
||||||
|
}
|
||||||
|
var values = properties.get(name);
|
||||||
|
if (values != null) {
|
||||||
|
Object value;
|
||||||
|
try {
|
||||||
|
value = Convert.toType(values, type);
|
||||||
|
} catch (ConversionException e) {
|
||||||
|
value = Convert.getDefaultValue(type);
|
||||||
|
}
|
||||||
|
field.set(element, value);
|
||||||
|
}
|
||||||
} else if (field.isAnnotationPresent(Header.class) &&
|
} else if (field.isAnnotationPresent(Header.class) &&
|
||||||
shouldProcessInFlow(field.getAnnotation(Header.class).flow())) {
|
shouldProcessInFlow(field.getAnnotation(Header.class).flow())) {
|
||||||
var annotation_name = field.getAnnotation(Header.class).value();
|
var annotation_name = field.getAnnotation(Header.class).value();
|
||||||
|
|
|
@ -79,12 +79,13 @@ public class RouteInstance implements Route {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field.isAnnotationPresent(ActiveSite.class) ||
|
if (field.isAnnotationPresent(ActiveSite.class) ||
|
||||||
field.isAnnotationPresent(Parameter.class) ||
|
|
||||||
field.isAnnotationPresent(Header.class) ||
|
|
||||||
field.isAnnotationPresent(Body.class) ||
|
field.isAnnotationPresent(Body.class) ||
|
||||||
field.isAnnotationPresent(PathInfo.class) ||
|
|
||||||
field.isAnnotationPresent(FileUpload.class) ||
|
|
||||||
field.isAnnotationPresent(Cookie.class) ||
|
field.isAnnotationPresent(Cookie.class) ||
|
||||||
|
field.isAnnotationPresent(FileUpload.class) ||
|
||||||
|
field.isAnnotationPresent(Header.class) ||
|
||||||
|
field.isAnnotationPresent(Parameter.class) ||
|
||||||
|
field.isAnnotationPresent(PathInfo.class) ||
|
||||||
|
field.isAnnotationPresent(Property.class) ||
|
||||||
field.isAnnotationPresent(RequestAttribute.class) ||
|
field.isAnnotationPresent(RequestAttribute.class) ||
|
||||||
field.isAnnotationPresent(SessionAttribute.class)) {
|
field.isAnnotationPresent(SessionAttribute.class)) {
|
||||||
throw new AnnotatedElementInstanceFieldException(this, element_, field.getName());
|
throw new AnnotatedElementInstanceFieldException(this, element_, field.getName());
|
||||||
|
|
|
@ -4,11 +4,14 @@
|
||||||
*/
|
*/
|
||||||
package rife.engine;
|
package rife.engine;
|
||||||
|
|
||||||
|
import rife.ioc.HierarchicalProperties;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class Router {
|
public class Router {
|
||||||
|
final HierarchicalProperties properties_ = new HierarchicalProperties();
|
||||||
final List<Route> before_ = new ArrayList<>();
|
final List<Route> before_ = new ArrayList<>();
|
||||||
final List<Route> after_ = new ArrayList<>();
|
final List<Route> after_ = new ArrayList<>();
|
||||||
final Map<String, List<Route>> routes_ = new HashMap<>();
|
final Map<String, List<Route>> routes_ = new HashMap<>();
|
||||||
|
@ -64,6 +67,7 @@ public class Router {
|
||||||
}
|
}
|
||||||
|
|
||||||
public final <T extends Router> T group(String path, T router) {
|
public final <T extends Router> T group(String path, T router) {
|
||||||
|
router.properties_.setParent(this.properties_);
|
||||||
router.parent_ = this;
|
router.parent_ = this;
|
||||||
groups_.add(router);
|
groups_.add(router);
|
||||||
|
|
||||||
|
@ -317,6 +321,10 @@ public class Router {
|
||||||
return route;
|
return route;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HierarchicalProperties properties() {
|
||||||
|
return properties_;
|
||||||
|
}
|
||||||
|
|
||||||
public Site site() {
|
public Site site() {
|
||||||
Router router = this;
|
Router router = this;
|
||||||
while (router.parent_ != null) {
|
while (router.parent_ != null) {
|
||||||
|
|
|
@ -8,11 +8,13 @@ import org.eclipse.jetty.server.*;
|
||||||
import org.eclipse.jetty.server.session.*;
|
import org.eclipse.jetty.server.session.*;
|
||||||
import org.eclipse.jetty.servlet.*;
|
import org.eclipse.jetty.servlet.*;
|
||||||
import rife.config.RifeConfig;
|
import rife.config.RifeConfig;
|
||||||
|
import rife.ioc.HierarchicalProperties;
|
||||||
import rife.servlet.RifeFilter;
|
import rife.servlet.RifeFilter;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
|
||||||
public class Server {
|
public class Server {
|
||||||
|
private final HierarchicalProperties properties_ = new HierarchicalProperties();
|
||||||
private final org.eclipse.jetty.server.Server server_ = new org.eclipse.jetty.server.Server();
|
private final org.eclipse.jetty.server.Server server_ = new org.eclipse.jetty.server.Server();
|
||||||
private final SessionIdManager sessions_ = new DefaultSessionIdManager(server_);
|
private final SessionIdManager sessions_ = new DefaultSessionIdManager(server_);
|
||||||
private final ServletContextHandler handler_ = new ServletContextHandler();
|
private final ServletContextHandler handler_ = new ServletContextHandler();
|
||||||
|
@ -27,6 +29,10 @@ public class Server {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HierarchicalProperties properties() {
|
||||||
|
return properties_;
|
||||||
|
}
|
||||||
|
|
||||||
public Server start(Site site) {
|
public Server start(Site site) {
|
||||||
try (var connector = new ServerConnector(server_)) {
|
try (var connector = new ServerConnector(server_)) {
|
||||||
connector.setPort(RifeConfig.server().getPort());
|
connector.setPort(RifeConfig.server().getPort());
|
||||||
|
@ -41,7 +47,7 @@ public class Server {
|
||||||
handler_.setSessionHandler(session_handler);
|
handler_.setSessionHandler(session_handler);
|
||||||
|
|
||||||
var rife_filter = new RifeFilter();
|
var rife_filter = new RifeFilter();
|
||||||
rife_filter.site(site);
|
rife_filter.site(properties_, site);
|
||||||
var filter_holder = new FilterHolder(rife_filter);
|
var filter_holder = new FilterHolder(rife_filter);
|
||||||
|
|
||||||
var ctx = new ServletContextHandler();
|
var ctx = new ServletContextHandler();
|
||||||
|
|
25
lib/src/main/java/rife/engine/annotations/Property.java
Normal file
25
lib/src/main/java/rife/engine/annotations/Property.java
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2001-2022 Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||||
|
*/
|
||||||
|
package rife.engine.annotations;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declares a property.
|
||||||
|
*
|
||||||
|
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target({ElementType.FIELD})
|
||||||
|
@Documented
|
||||||
|
public @interface Property {
|
||||||
|
/**
|
||||||
|
* The name of the parameter.
|
||||||
|
*
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
String value() default "";
|
||||||
|
}
|
676
lib/src/main/java/rife/ioc/HierarchicalProperties.java
Normal file
676
lib/src/main/java/rife/ioc/HierarchicalProperties.java
Normal file
|
@ -0,0 +1,676 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2001-2022 Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||||
|
*/
|
||||||
|
package rife.ioc;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import rife.ioc.exceptions.IncompatiblePropertyValueTypeException;
|
||||||
|
import rife.ioc.exceptions.PropertyValueException;
|
||||||
|
|
||||||
|
import java.text.CharacterIterator;
|
||||||
|
import java.text.StringCharacterIterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class allows the creation of a hierarchical tree of named {@link
|
||||||
|
* PropertyValue} instances.
|
||||||
|
* <p>When a property is looked up in a child
|
||||||
|
* <code>HierarchicalProperties</code> instance, the lookup will be propagated
|
||||||
|
* to its parent when it couldn't be found in the child. A single hierarchical
|
||||||
|
* line is thus considered to be one collection that groups all involved
|
||||||
|
* <code>HierarchicalProperties</code> instances. Retrieving the names and the
|
||||||
|
* size will recursively take all the properties of the parents into account
|
||||||
|
* and return the consolidated result. To offer these features, intelligent
|
||||||
|
* caching has been implemented to ensure optimal performance.
|
||||||
|
*
|
||||||
|
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public class HierarchicalProperties {
|
||||||
|
private LinkedHashMap<String, PropertyValue> properties_;
|
||||||
|
|
||||||
|
private HierarchicalProperties parent_;
|
||||||
|
private LinkedHashSet<HierarchicalProperties> children_;
|
||||||
|
private Set<String> cachedNames_;
|
||||||
|
private Set<String> cachedInjectableNames_;
|
||||||
|
|
||||||
|
public HierarchicalProperties() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private HierarchicalProperties(HierarchicalProperties shadow) {
|
||||||
|
properties_ = shadow.properties_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a copy of this <code>HierarchicalProperties</code> hierarchy
|
||||||
|
* until a certain instance is reached.
|
||||||
|
* <p>
|
||||||
|
* Each copied instance will share the datastructure in which the
|
||||||
|
* properties are stored with the original. Creating a shadow is for
|
||||||
|
* changing the hierarchical structure but maintaining a centralized
|
||||||
|
* management of the properties.
|
||||||
|
*
|
||||||
|
* @param limit the <code>HierarchicalProperties</code> instance that will
|
||||||
|
* not be part of the shadow copy and interrupt the copying process; or
|
||||||
|
* <code>null</code> if the entire hierachy should be copied.
|
||||||
|
* @return the shadow copy of this <code>HierarchicalProperties</code>
|
||||||
|
* hierarchy
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public HierarchicalProperties createShadow(HierarchicalProperties limit) {
|
||||||
|
var result = new HierarchicalProperties(this);
|
||||||
|
|
||||||
|
var original = this;
|
||||||
|
var shadow = result;
|
||||||
|
while (original.getParent() != null &&
|
||||||
|
original.getParent() != limit) {
|
||||||
|
shadow.setParent(new HierarchicalProperties(original.getParent()));
|
||||||
|
original = original.getParent();
|
||||||
|
shadow = shadow.getParent();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the first parent of this <code>HierarchicalProperties</code>
|
||||||
|
* hierarchy.
|
||||||
|
*
|
||||||
|
* @return the root of this <code>HierarchicalProperties</code>
|
||||||
|
* hierarchy
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public HierarchicalProperties getRoot() {
|
||||||
|
var root = this;
|
||||||
|
while (root.getParent() != null) {
|
||||||
|
root = root.getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the <code>Map</code> with only the properties that are
|
||||||
|
* locally present in this <code>HierarchicalProperties</code> instance.
|
||||||
|
*
|
||||||
|
* @return the local <code>Map</code> of this
|
||||||
|
* <code>HierarchicalProperties</code> instance
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public Map<String, PropertyValue> getLocalMap() {
|
||||||
|
if (null == properties_) {
|
||||||
|
return Collections.EMPTY_MAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return properties_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the parent of this <code>HierarchicalProperties</code> instance.
|
||||||
|
*
|
||||||
|
* @param parent the parent of this instance; or <code>null</code> if this
|
||||||
|
* instance should be isolated
|
||||||
|
* @see #getParent
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public void setParent(HierarchicalProperties parent) {
|
||||||
|
clearCaches();
|
||||||
|
|
||||||
|
if (parent_ != null) {
|
||||||
|
parent_.removeChild(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
parent_ = parent;
|
||||||
|
|
||||||
|
if (parent_ != null) {
|
||||||
|
parent_.addChild(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the parent of this <code>HierarchicalProperties</code> instance.
|
||||||
|
*
|
||||||
|
* @param parent the parent of this instance; or <code>null</code> if this
|
||||||
|
* instance should be isolated
|
||||||
|
* @return this <code>HierarchicalProperties</code> instance
|
||||||
|
* @see #getParent
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public HierarchicalProperties parent(HierarchicalProperties parent) {
|
||||||
|
setParent(parent);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the parent of this <code>HierarchicalProperties</code>
|
||||||
|
* instance.
|
||||||
|
*
|
||||||
|
* @return the parent of this <code>HierarchicalProperties</code>
|
||||||
|
* instance; or
|
||||||
|
* <p><code>null</code> if this instance is isolated
|
||||||
|
* @see #parent
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public HierarchicalProperties getParent() {
|
||||||
|
return parent_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Associates the specified value with the specified name in this
|
||||||
|
* <code>HierarchicalProperties</code> instance. If it previously
|
||||||
|
* contained a mapping for this name, the old value is replaced by the
|
||||||
|
* specified value.
|
||||||
|
*
|
||||||
|
* @param name the name that will be associated with the property
|
||||||
|
* @param value the property value that will be associated with the
|
||||||
|
* specified name
|
||||||
|
* @return this <code>HierarchicalProperties</code> instance
|
||||||
|
* @see #put(String, Object)
|
||||||
|
* @see #putAll
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public HierarchicalProperties put(String name, PropertyValue value) {
|
||||||
|
clearCaches();
|
||||||
|
|
||||||
|
if (null == properties_) {
|
||||||
|
properties_ = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
properties_.put(name, value);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Associates the specified fixed object value with the specified name
|
||||||
|
* in this <code>HierarchicalProperties</code> instance. If it previously
|
||||||
|
* contained a mapping for this name, the old value is replaced by the
|
||||||
|
* specified value.
|
||||||
|
*
|
||||||
|
* @param name the name that will be associated with the property
|
||||||
|
* @param value the property value that will be associated with the
|
||||||
|
* specified name, note that this method will create a {@link PropertyValueObject}
|
||||||
|
* instance that will contain the value in a fixed manner
|
||||||
|
* @return this <code>HierarchicalProperties</code> instance
|
||||||
|
* @see #put(String, PropertyValue)
|
||||||
|
* @see #putAll
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public HierarchicalProperties put(String name, Object value) {
|
||||||
|
put(name, new PropertyValueObject(value));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the mapping for this name from this
|
||||||
|
* <code>HierarchicalProperties</code> instance, if it is present.
|
||||||
|
*
|
||||||
|
* @param name the name that will be removed
|
||||||
|
* @return the previously associated value; or
|
||||||
|
* <p><code>null</code> if the name wasn't found in this
|
||||||
|
* <code>HierarchicalProperties</code> instance
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public PropertyValue remove(String name) {
|
||||||
|
if (null == properties_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCaches();
|
||||||
|
|
||||||
|
return properties_.remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies all the named properties from the specified
|
||||||
|
* <code>HierarchicalProperties</code> instance to this
|
||||||
|
* <code>HierarchicalProperties</code> instance. The effect of this call
|
||||||
|
* is equivalent to that of calling {@link #put} on this
|
||||||
|
* <code>HierarchicalProperties</code> once for each mapping from the
|
||||||
|
* specified <code>HierarchicalProperties</code> instance.
|
||||||
|
*
|
||||||
|
* @param source the properties that will be stored in this
|
||||||
|
* <code>HierarchicalProperties</code> instance
|
||||||
|
* @return this <code>HierarchicalProperties</code> instance
|
||||||
|
* @see #put
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public HierarchicalProperties putAll(HierarchicalProperties source) {
|
||||||
|
clearCaches();
|
||||||
|
|
||||||
|
if (source.properties_ != null) {
|
||||||
|
if (null == properties_) {
|
||||||
|
properties_ = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
properties_.putAll(source.properties_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies all the named properties from the specified
|
||||||
|
* <code>HierarchicalProperties</code> instance to this
|
||||||
|
* <code>HierarchicalProperties</code> instance, without replacing existing
|
||||||
|
* properties. The effect of this call
|
||||||
|
* is equivalent to that of calling {@link #put} on this
|
||||||
|
* <code>HierarchicalProperties</code> once for each mapping from the
|
||||||
|
* specified <code>HierarchicalProperties</code> instance that doesn't
|
||||||
|
* have a key in this instance yet.
|
||||||
|
*
|
||||||
|
* @param source the properties that will be stored in this
|
||||||
|
* <code>HierarchicalProperties</code> instance
|
||||||
|
* @return this <code>HierarchicalProperties</code> instance
|
||||||
|
* @see #put
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public HierarchicalProperties putAllWithoutReplacing(HierarchicalProperties source) {
|
||||||
|
clearCaches();
|
||||||
|
|
||||||
|
if (source.properties_ != null) {
|
||||||
|
if (null == properties_) {
|
||||||
|
properties_ = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var entry : source.properties_.entrySet()) {
|
||||||
|
if (!properties_.containsKey(entry.getKey())) {
|
||||||
|
properties_.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies all the entries for a <code>Map</code> instance to this
|
||||||
|
* <code>HierarchicalProperties</code> instance.
|
||||||
|
*
|
||||||
|
* @param source the map entries that will be stored in this
|
||||||
|
* <code>HierarchicalProperties</code> instance
|
||||||
|
* @return this <code>HierarchicalProperties</code> instance
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public HierarchicalProperties putAll(Map source) {
|
||||||
|
if (null == source) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCaches();
|
||||||
|
|
||||||
|
if (null == properties_) {
|
||||||
|
properties_ = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var entry : ((Set<Map.Entry>) source.entrySet())) {
|
||||||
|
properties_.put(String.valueOf(entry.getKey()), new PropertyValueObject(entry.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the <code>HierarchicalProperties</code> hierarchy for the
|
||||||
|
* presence of the specified name.
|
||||||
|
*
|
||||||
|
* @param name the name whose presence will be checked
|
||||||
|
* @return <code>true</code> if the name was found; or
|
||||||
|
* <p><code>false</code> otherwise
|
||||||
|
* @see #get
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public boolean contains(String name) {
|
||||||
|
var current = this;
|
||||||
|
|
||||||
|
LinkedHashMap<String, PropertyValue> properties = null;
|
||||||
|
while (true) {
|
||||||
|
properties = current.properties_;
|
||||||
|
|
||||||
|
if (properties != null) {
|
||||||
|
if (properties.containsKey(name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null == current.parent_) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current.parent_;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the <code>PropertyValue</code> for a specific name from the
|
||||||
|
* <code>HierarchicalProperties</code> hierarchy.
|
||||||
|
*
|
||||||
|
* @param name the name whose associated value will be returned
|
||||||
|
* @return the associated <code>PropertyValue</code>; or
|
||||||
|
* <p><code>null</code> if the name could not be found
|
||||||
|
* @see #contains
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public PropertyValue get(String name) {
|
||||||
|
var current = this;
|
||||||
|
PropertyValue result;
|
||||||
|
|
||||||
|
LinkedHashMap<String, PropertyValue> properties = null;
|
||||||
|
while (true) {
|
||||||
|
properties = current.properties_;
|
||||||
|
|
||||||
|
if (properties != null) {
|
||||||
|
result = properties.get(name);
|
||||||
|
if (result != null) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null == current.parent_) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current.parent_;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the value of <code>PropertyValue</code> for a specific name from
|
||||||
|
* the <code>HierarchicalProperties</code> hierarchy.
|
||||||
|
*
|
||||||
|
* @param name the name whose associated value will be returned
|
||||||
|
* @return the associated <code>PropertyValue</code>; or
|
||||||
|
* <p><code>null</code> if the name could not be found
|
||||||
|
* @throws PropertyValueException when an error occurred while retrieving the
|
||||||
|
* property value
|
||||||
|
* @see #get
|
||||||
|
* @see #getValue(String, Object)
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public Object getValue(String name)
|
||||||
|
throws PropertyValueException {
|
||||||
|
return getValue(name, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the value of <code>PropertyValue</code> for a specific name from
|
||||||
|
* the <code>HierarchicalProperties</code> hierarchy. If the property couldn't
|
||||||
|
* be found or if the value was <code>null</code>, the default value will be
|
||||||
|
* returned.
|
||||||
|
*
|
||||||
|
* @param name the name whose associated value will be returned
|
||||||
|
* @param defaultValue the value that should be used as a fallback
|
||||||
|
* @return the associated <code>PropertyValue</code>; or
|
||||||
|
* <p>the <code>defaultValue</code> if the property couldn't be found or if
|
||||||
|
* the value was <code>null</code>
|
||||||
|
* @throws PropertyValueException when an error occurred while retrieving the
|
||||||
|
* property value
|
||||||
|
* @see #get
|
||||||
|
* @see #getValue(String)
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public Object getValue(String name, Object defaultValue)
|
||||||
|
throws PropertyValueException {
|
||||||
|
Object result = null;
|
||||||
|
|
||||||
|
var property = get(name);
|
||||||
|
if (property != null) {
|
||||||
|
result = property.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null == result) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the string value of <code>PropertyValue</code> for a specific name from
|
||||||
|
* the <code>HierarchicalProperties</code> hierarchy.
|
||||||
|
*
|
||||||
|
* @param name the name whose associated value will be returned
|
||||||
|
* @return the string value of the retrieved <code>PropertyValue</code>; or
|
||||||
|
* <p><code>null</code> if the name could not be found
|
||||||
|
* @throws PropertyValueException when an error occurred while retrieving the
|
||||||
|
* property value
|
||||||
|
* @see #get
|
||||||
|
* @see #getValueString(String, String)
|
||||||
|
* @see #getValueTyped
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public String getValueString(String name)
|
||||||
|
throws PropertyValueException {
|
||||||
|
return getValueString(name, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the string value of <code>PropertyValue</code> for a specific name from
|
||||||
|
* the <code>HierarchicalProperties</code> hierarchy. If the property couldn't
|
||||||
|
* be found, if the value was <code>null</code> or if the value was empty, the
|
||||||
|
* default value will be returned.
|
||||||
|
*
|
||||||
|
* @param name the name whose associated value will be returned
|
||||||
|
* @param defaultValue the value that should be used as a fallback
|
||||||
|
* @return the string value of the retrieved <code>PropertyValue</code>; or
|
||||||
|
* <p>the <code>defaultValue</code> if the property couldn't be found or if
|
||||||
|
* the value was <code>null</code> or an empty string
|
||||||
|
* @throws PropertyValueException when an error occurred while retrieving the
|
||||||
|
* property value
|
||||||
|
* @see #get
|
||||||
|
* @see #getValueString(String)
|
||||||
|
* @see #getValueTyped
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public String getValueString(String name, String defaultValue)
|
||||||
|
throws PropertyValueException {
|
||||||
|
String result = null;
|
||||||
|
|
||||||
|
var property = get(name);
|
||||||
|
if (property != null) {
|
||||||
|
result = property.getValueString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null == result ||
|
||||||
|
0 == result.length()) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the typed value of <code>PropertyValue</code> for a specific name from
|
||||||
|
* the <code>HierarchicalProperties</code> hierarchy.
|
||||||
|
* <p>
|
||||||
|
* Note that no conversion will occurr, the value is simple verified to be
|
||||||
|
* assignable to the requested type and then cast to it.
|
||||||
|
*
|
||||||
|
* @param name the name whose associated value will be returned
|
||||||
|
* @param type the class that the value has to be retrieved as
|
||||||
|
* @return the associated <code>PropertyValue</code> as an instance of the
|
||||||
|
* provided type; or
|
||||||
|
* <p><code>null</code> if the name could not be found
|
||||||
|
* @throws IncompatiblePropertyValueTypeException when the type of the property
|
||||||
|
* value wasn't compatible with the requested type
|
||||||
|
* @throws PropertyValueException when an error occurred while retrieving the
|
||||||
|
* property value
|
||||||
|
* @see #get
|
||||||
|
* @see #getValueString
|
||||||
|
* @see #getValueTyped(String, Class)
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public <T> T getValueTyped(String name, Class<T> type)
|
||||||
|
throws PropertyValueException {
|
||||||
|
return (T) getValueTyped(name, type, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the typed value of <code>PropertyValue</code> for a specific name from
|
||||||
|
* the <code>HierarchicalProperties</code> hierarchy.
|
||||||
|
* <p>
|
||||||
|
* Note that no conversion will occur, the value is simple verified to be
|
||||||
|
* assignable to the requested type and then cast to it.
|
||||||
|
*
|
||||||
|
* @param name the name whose associated value will be returned
|
||||||
|
* @param type the class that the value has to be retrieved as
|
||||||
|
* @param defaultValue the value that should be used as a fallback
|
||||||
|
* @return the associated <code>PropertyValue</code> as an instance of the
|
||||||
|
* provided type; or
|
||||||
|
* <p>the <code>defaultValue</code> if the property couldn't be found or if
|
||||||
|
* the value was <code>null</code>
|
||||||
|
* @throws IncompatiblePropertyValueTypeException when the type of the property
|
||||||
|
* value wasn't compatible with the requested type
|
||||||
|
* @throws PropertyValueException when an error occurred while retrieving the
|
||||||
|
* property value
|
||||||
|
* @see #get
|
||||||
|
* @see #getValueString
|
||||||
|
* @see #getValueTyped(String, Class)
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public <T> T getValueTyped(String name, Class<T> type, T defaultValue)
|
||||||
|
throws PropertyValueException {
|
||||||
|
if (null == name ||
|
||||||
|
null == type ||
|
||||||
|
0 == name.length()) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object result = null;
|
||||||
|
|
||||||
|
var property = get(name);
|
||||||
|
if (property != null) {
|
||||||
|
result = property.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null == result) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!type.isAssignableFrom(result.getClass())) {
|
||||||
|
throw new IncompatiblePropertyValueTypeException(name, type, result.getClass(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (T) result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the number of unique names in the
|
||||||
|
* <code>HierarchicalProperties</code> hierarchy.
|
||||||
|
*
|
||||||
|
* @return the amount of unique names
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public int size() {
|
||||||
|
return getNames().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a <code>Set</code> with the unique names that are present in
|
||||||
|
* the <code>HierarchicalProperties</code> hierarchy.
|
||||||
|
*
|
||||||
|
* @return a collection with the unique names
|
||||||
|
* @see #getInjectableNames
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public Collection<String> getNames() {
|
||||||
|
if (cachedNames_ != null) {
|
||||||
|
return cachedNames_;
|
||||||
|
}
|
||||||
|
|
||||||
|
var current = this;
|
||||||
|
Set<String> names = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
LinkedHashMap<String, PropertyValue> properties = null;
|
||||||
|
while (true) {
|
||||||
|
properties = current.properties_;
|
||||||
|
|
||||||
|
if (properties != null) {
|
||||||
|
names.addAll(properties.keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null == current.parent_) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current.parent_;
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedNames_ = names;
|
||||||
|
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a <code>Set</code> with the unique names that are present in
|
||||||
|
* the <code>HierarchicalProperties</code> hierarchy and that conform to
|
||||||
|
* the <a
|
||||||
|
* href="http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.8">Java
|
||||||
|
* rules for valid identifiers</a>. The names in this set are thus usable
|
||||||
|
* for injection through bean setters.
|
||||||
|
*
|
||||||
|
* @return a <code>Set</code> with the unique injectable names
|
||||||
|
* @see #getNames
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public Collection<String> getInjectableNames() {
|
||||||
|
if (cachedInjectableNames_ != null) {
|
||||||
|
return cachedInjectableNames_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> injectable_names = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
var names = getNames();
|
||||||
|
for (var name : names) {
|
||||||
|
var injectable = true;
|
||||||
|
CharacterIterator it = new StringCharacterIterator(name);
|
||||||
|
for (var c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
|
||||||
|
if (!Character.isJavaIdentifierPart(c)) {
|
||||||
|
injectable = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (injectable) {
|
||||||
|
injectable_names.add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedInjectableNames_ = injectable_names;
|
||||||
|
|
||||||
|
return injectable_names;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearCaches() {
|
||||||
|
cachedNames_ = null;
|
||||||
|
cachedInjectableNames_ = null;
|
||||||
|
|
||||||
|
if (null == children_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var child : children_) {
|
||||||
|
child.clearCaches();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addChild(HierarchicalProperties child) {
|
||||||
|
if (null == children_) {
|
||||||
|
children_ = new LinkedHashSet<>();
|
||||||
|
}
|
||||||
|
children_.add(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeChild(HierarchicalProperties child) {
|
||||||
|
if (null == children_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
children_.remove(child);
|
||||||
|
}
|
||||||
|
}
|
68
lib/src/main/java/rife/ioc/PropertyValue.java
Normal file
68
lib/src/main/java/rife/ioc/PropertyValue.java
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2001-2022 Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||||
|
*/
|
||||||
|
package rife.ioc;
|
||||||
|
|
||||||
|
import rife.ioc.exceptions.PropertyValueException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface defines the methods that need to be implemented by classes
|
||||||
|
* that are able to provide values to properties.
|
||||||
|
* <p>These classes should make all value retrieval as lazy as possible and
|
||||||
|
* store only the parameters that are required to obtain the actual data
|
||||||
|
* dynamically at runtime.
|
||||||
|
*
|
||||||
|
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public interface PropertyValue {
|
||||||
|
/**
|
||||||
|
* Retrieves a property value.
|
||||||
|
*
|
||||||
|
* @return the requested property value; or
|
||||||
|
* <p><code>null</code> if the property value couldn't be found
|
||||||
|
* @throws PropertyValueException When something went wrong during the
|
||||||
|
* retrieval of the property value.
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
Object getValue()
|
||||||
|
throws PropertyValueException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a string representation of the property value.
|
||||||
|
*
|
||||||
|
* @return the requested string representation of the property value; or
|
||||||
|
* <p><code>null</code> if the property value couldn't be found
|
||||||
|
* @throws PropertyValueException When something went wrong during the
|
||||||
|
* retrieval of the property value.
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
String getValueString()
|
||||||
|
throws PropertyValueException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether the value provided by this instance is negligible in
|
||||||
|
* a textual context. This is for instance applicable to pure whitespace
|
||||||
|
* values that when trimmed, have zero length. The property construction
|
||||||
|
* logic will check this state to determine if it has to concatenate
|
||||||
|
* several property values together as one text result of only use one and
|
||||||
|
* discard all other negligible ones.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if the value is negligible in a textual
|
||||||
|
* context; or
|
||||||
|
* <p><code>false</code> otherwise
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
boolean isNegligible();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether the value is statically fixed an not dynamically
|
||||||
|
* retrieved at runtime.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if the value is static; or
|
||||||
|
* <p><code>false</code> if the value is dynamically retrieved at runtime
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
boolean isStatic();
|
||||||
|
}
|
65
lib/src/main/java/rife/ioc/PropertyValueList.java
Normal file
65
lib/src/main/java/rife/ioc/PropertyValueList.java
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2001-2022 Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||||
|
*/
|
||||||
|
package rife.ioc;
|
||||||
|
|
||||||
|
import rife.ioc.exceptions.PropertyValueException;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ordered list of property values.
|
||||||
|
*
|
||||||
|
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public class PropertyValueList extends ArrayList<PropertyValue> {
|
||||||
|
@Serial private static final long serialVersionUID = -7791482346118685259L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interprets the list of property values and make one new property value
|
||||||
|
* out of it.
|
||||||
|
*
|
||||||
|
* @return the new <code>PropertyValue</code> instance
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public PropertyValue makePropertyValue()
|
||||||
|
throws PropertyValueException {
|
||||||
|
// evaluate the current property values series and check if this should be
|
||||||
|
// interpreted as a text result or as a participant value
|
||||||
|
PropertyValue result = null;
|
||||||
|
|
||||||
|
PropertyValue non_negligible_prop_val = null;
|
||||||
|
for (var prop_val : this) {
|
||||||
|
if (!prop_val.isNegligible()) {
|
||||||
|
if (non_negligible_prop_val != null) {
|
||||||
|
non_negligible_prop_val = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
non_negligible_prop_val = prop_val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (non_negligible_prop_val != null) {
|
||||||
|
if (non_negligible_prop_val instanceof PropertyValueObject ||
|
||||||
|
!non_negligible_prop_val.isStatic()) {
|
||||||
|
result = non_negligible_prop_val;
|
||||||
|
} else {
|
||||||
|
result = new PropertyValueObject(non_negligible_prop_val.getValueString().trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null == result) {
|
||||||
|
var key_text = new StringBuilder();
|
||||||
|
for (var prop_val : this) {
|
||||||
|
key_text.append(prop_val.getValueString());
|
||||||
|
}
|
||||||
|
result = new PropertyValueObject(key_text.toString().trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
51
lib/src/main/java/rife/ioc/PropertyValueObject.java
Normal file
51
lib/src/main/java/rife/ioc/PropertyValueObject.java
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2001-2022 Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||||
|
*/
|
||||||
|
package rife.ioc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds a single static object property value that doesn't change at runtime.
|
||||||
|
*
|
||||||
|
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public class PropertyValueObject implements PropertyValue {
|
||||||
|
private final Object value_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The constructor that stores the static object instance.
|
||||||
|
*
|
||||||
|
* @param value the static object instance
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public PropertyValueObject(Object value) {
|
||||||
|
value_ = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getValue() {
|
||||||
|
return value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValueString() {
|
||||||
|
return String.valueOf(value_);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return getValueString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNegligible() {
|
||||||
|
if (null == value_) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0 == String.valueOf(value_).trim().length();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStatic() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
74
lib/src/main/java/rife/ioc/PropertyValueTemplate.java
Normal file
74
lib/src/main/java/rife/ioc/PropertyValueTemplate.java
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2001-2022 Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||||
|
*/
|
||||||
|
package rife.ioc;
|
||||||
|
|
||||||
|
import rife.ioc.exceptions.PropertyValueException;
|
||||||
|
import rife.ioc.exceptions.TemplateFactoryUnknownException;
|
||||||
|
import rife.template.Template;
|
||||||
|
import rife.template.TemplateFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a property value as template instance of a particular type.
|
||||||
|
*
|
||||||
|
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public class PropertyValueTemplate implements PropertyValue {
|
||||||
|
private final String type_;
|
||||||
|
private final String name_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The constructor that stores the retrieval parameters.
|
||||||
|
* The template type will be set to "html"
|
||||||
|
*
|
||||||
|
* @param name the template name
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public PropertyValueTemplate(String name) {
|
||||||
|
this(null, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The constructor that stores the retrieval parameters.
|
||||||
|
*
|
||||||
|
* @param type the template factory type; if this argument is <code>null</code>
|
||||||
|
* the template type will be "html"
|
||||||
|
* @param name the template name
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public PropertyValueTemplate(String type, String name) {
|
||||||
|
if (null == type) {
|
||||||
|
type = "html";
|
||||||
|
}
|
||||||
|
type_ = type;
|
||||||
|
name_ = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Template getValue()
|
||||||
|
throws PropertyValueException {
|
||||||
|
TemplateFactory factory = TemplateFactory.getFactory(type_);
|
||||||
|
if (null == factory) {
|
||||||
|
throw new TemplateFactoryUnknownException(type_);
|
||||||
|
}
|
||||||
|
return factory.get(name_);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValueString()
|
||||||
|
throws PropertyValueException {
|
||||||
|
return getValue().getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return getValueString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNegligible() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStatic() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2001-2022 Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||||
|
*/
|
||||||
|
package rife.ioc.exceptions;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
|
public class IncompatiblePropertyValueTypeException extends PropertyValueException {
|
||||||
|
@Serial private static final long serialVersionUID = 6336950082309925343L;
|
||||||
|
|
||||||
|
private final String propertyName_;
|
||||||
|
private final Class expectedType_;
|
||||||
|
private final Class actualType_;
|
||||||
|
|
||||||
|
public IncompatiblePropertyValueTypeException(String propertyName, Class expectedType, Class actualType, Throwable e) {
|
||||||
|
super("The property '" + propertyName + "' was expected to have the type '" + expectedType.getName() + "', however it's actual type '" + actualType.getName() + "' couldn't be cast to it.", e);
|
||||||
|
|
||||||
|
propertyName_ = propertyName;
|
||||||
|
expectedType_ = expectedType;
|
||||||
|
actualType_ = actualType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPropertyName() {
|
||||||
|
return propertyName_;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class getExpectedType() {
|
||||||
|
return expectedType_;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class getActualType() {
|
||||||
|
return actualType_;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2001-2022 Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||||
|
*/
|
||||||
|
package rife.ioc.exceptions;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
|
public class PropertyValueException extends RuntimeException {
|
||||||
|
@Serial private static final long serialVersionUID = 1712906301485959756L;
|
||||||
|
|
||||||
|
public PropertyValueException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyValueException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyValueException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyValueException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2001-2022 Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||||
|
*/
|
||||||
|
package rife.ioc.exceptions;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
|
public class TemplateFactoryUnknownException extends PropertyValueException {
|
||||||
|
@Serial private static final long serialVersionUID = 7268695167543687153L;
|
||||||
|
|
||||||
|
private final String type_;
|
||||||
|
|
||||||
|
public TemplateFactoryUnknownException(String type) {
|
||||||
|
super("The template factory with type '" + type + "' isn't known by the system.");
|
||||||
|
|
||||||
|
type_ = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type_;
|
||||||
|
}
|
||||||
|
}
|
7
lib/src/main/java/rife/ioc/exceptions/package.html
Normal file
7
lib/src/main/java/rife/ioc/exceptions/package.html
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
Provides exception classes for the inversion of control support.
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
7
lib/src/main/java/rife/ioc/package.html
Normal file
7
lib/src/main/java/rife/ioc/package.html
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
Provides interfaces and classes for IoC capable properties that resolve and obtain their values at run-time.
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -10,6 +10,7 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||||
import rife.config.RifeConfig;
|
import rife.config.RifeConfig;
|
||||||
import rife.engine.Gate;
|
import rife.engine.Gate;
|
||||||
import rife.engine.Site;
|
import rife.engine.Site;
|
||||||
|
import rife.ioc.HierarchicalProperties;
|
||||||
import rife.tools.FileUtils;
|
import rife.tools.FileUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -20,8 +21,8 @@ public class RifeFilter implements Filter {
|
||||||
private final Gate gate_ = new Gate();
|
private final Gate gate_ = new Gate();
|
||||||
private String gateUrl_ = null;
|
private String gateUrl_ = null;
|
||||||
|
|
||||||
public void site(Site site) {
|
public void site(HierarchicalProperties properties, Site site) {
|
||||||
gate_.setup(site);
|
gate_.setup(properties, site);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -29,11 +30,29 @@ public class RifeFilter implements Filter {
|
||||||
throws ServletException {
|
throws ServletException {
|
||||||
var classloader = getClass().getClassLoader();
|
var classloader = getClass().getClassLoader();
|
||||||
|
|
||||||
|
// set up the properties
|
||||||
|
var properties = new HierarchicalProperties();
|
||||||
|
|
||||||
|
var context = config.getServletContext();
|
||||||
|
var names = context.getInitParameterNames();
|
||||||
|
String name;
|
||||||
|
while (names.hasMoreElements()) {
|
||||||
|
name = names.nextElement();
|
||||||
|
properties.put(name, context.getInitParameter(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
names = config.getInitParameterNames();
|
||||||
|
while (names.hasMoreElements()) {
|
||||||
|
name = names.nextElement();
|
||||||
|
properties.put(name, config.getInitParameter(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the site instance
|
||||||
var site_classname = config.getInitParameter(RIFE_SITE_CLASS_NAME);
|
var site_classname = config.getInitParameter(RIFE_SITE_CLASS_NAME);
|
||||||
if (site_classname != null) {
|
if (site_classname != null) {
|
||||||
try {
|
try {
|
||||||
var site_class = classloader.loadClass(site_classname);
|
var site_class = classloader.loadClass(site_classname);
|
||||||
gate_.setup((Site) site_class.getDeclaredConstructor().newInstance());
|
gate_.setup(properties, (Site) site_class.getDeclaredConstructor().newInstance());
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
throw new ServletException(e);
|
throw new ServletException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import jakarta.servlet.http.Cookie;
|
||||||
import rife.engine.Gate;
|
import rife.engine.Gate;
|
||||||
import rife.engine.Site;
|
import rife.engine.Site;
|
||||||
import rife.engine.exceptions.EngineException;
|
import rife.engine.exceptions.EngineException;
|
||||||
|
import rife.ioc.HierarchicalProperties;
|
||||||
import rife.tools.ArrayUtils;
|
import rife.tools.ArrayUtils;
|
||||||
import rife.tools.StringUtils;
|
import rife.tools.StringUtils;
|
||||||
|
|
||||||
|
@ -31,6 +32,7 @@ public class MockConversation {
|
||||||
|
|
||||||
private Gate gate_ = null;
|
private Gate gate_ = null;
|
||||||
|
|
||||||
|
private final HierarchicalProperties properties_ = new HierarchicalProperties();
|
||||||
private final HashMap<String, MockCookie> cookies_ = new HashMap<>();
|
private final HashMap<String, MockCookie> cookies_ = new HashMap<>();
|
||||||
private final HashMap<String, MockSession> sessions_ = new HashMap<>();
|
private final HashMap<String, MockSession> sessions_ = new HashMap<>();
|
||||||
private String scheme_ = "http";
|
private String scheme_ = "http";
|
||||||
|
@ -48,7 +50,8 @@ public class MockConversation {
|
||||||
public MockConversation(Site site)
|
public MockConversation(Site site)
|
||||||
throws EngineException {
|
throws EngineException {
|
||||||
gate_ = new Gate();
|
gate_ = new Gate();
|
||||||
gate_.setup(site);
|
|
||||||
|
gate_.setup(properties_, site);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -292,6 +295,17 @@ public class MockConversation {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the properties uses by this conversation.
|
||||||
|
*
|
||||||
|
* @return the instance of <code>HierarchicalProperties</code> that is used
|
||||||
|
* by this conversation
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public HierarchicalProperties properties() {
|
||||||
|
return properties_;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether a cookie is present.
|
* Checks whether a cookie is present.
|
||||||
*
|
*
|
||||||
|
|
|
@ -25,6 +25,9 @@ public class AnnotationInSite extends Site {
|
||||||
@RequestAttribute int intRequestAttribute = -7;
|
@RequestAttribute int intRequestAttribute = -7;
|
||||||
@SessionAttribute int intSessionAttribute = -9;
|
@SessionAttribute int intSessionAttribute = -9;
|
||||||
@Header("header2") String stringHeader2 = "defaultHeader2";
|
@Header("header2") String stringHeader2 = "defaultHeader2";
|
||||||
|
@Property String prop1 = "defaultProp1";
|
||||||
|
@Property String prop2 = "defaultProp2";
|
||||||
|
@Property("prop1") String prop3 = "defaultProp3";
|
||||||
|
|
||||||
public void process(Context c)
|
public void process(Context c)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
@ -66,6 +69,10 @@ public class AnnotationInSite extends Site {
|
||||||
@Header int intHeader = -11;
|
@Header int intHeader = -11;
|
||||||
@Header("header3") int intHeader2 = -12;
|
@Header("header3") int intHeader2 = -12;
|
||||||
|
|
||||||
|
@Property String prop1 = "defaultProp1";
|
||||||
|
@Property String prop2 = "defaultProp2";
|
||||||
|
@Property("prop1") String prop3 = "defaultProp3";
|
||||||
|
|
||||||
public void process(Context c)
|
public void process(Context c)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
super.process(c);
|
super.process(c);
|
||||||
|
@ -133,10 +140,15 @@ public class AnnotationInSite extends Site {
|
||||||
c.print(intHeader + "\n");
|
c.print(intHeader + "\n");
|
||||||
c.print(stringHeader2 + "\n");
|
c.print(stringHeader2 + "\n");
|
||||||
c.print(intHeader2 + "\n");
|
c.print(intHeader2 + "\n");
|
||||||
|
|
||||||
|
c.print(prop1 + "\n");
|
||||||
|
c.print(prop2 + "\n");
|
||||||
|
c.print(prop3 + "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setup() {
|
public void setup() {
|
||||||
|
properties().put("prop1", "propval1");
|
||||||
before(c -> {
|
before(c -> {
|
||||||
if (c.parameterBoolean("generate")) {
|
if (c.parameterBoolean("generate")) {
|
||||||
c.setAttribute("stringRequestAttribute", "value9");
|
c.setAttribute("stringRequestAttribute", "value9");
|
||||||
|
|
|
@ -54,6 +54,9 @@ public class TestAnnotations {
|
||||||
-11
|
-11
|
||||||
defaultHeader2
|
defaultHeader2
|
||||||
-12
|
-12
|
||||||
|
propval1
|
||||||
|
defaultProp2
|
||||||
|
propval1
|
||||||
""", webClient.getPage(new WebRequest(new URL("http://localhost:8181/get"), HttpMethod.GET)).getWebResponse().getContentAsString());
|
""", webClient.getPage(new WebRequest(new URL("http://localhost:8181/get"), HttpMethod.GET)).getWebResponse().getContentAsString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,6 +113,9 @@ public class TestAnnotations {
|
||||||
18
|
18
|
||||||
value19
|
value19
|
||||||
20
|
20
|
||||||
|
propval1
|
||||||
|
defaultProp2
|
||||||
|
propval1
|
||||||
""", webClient.getPage(request).getWebResponse().getContentAsString());
|
""", webClient.getPage(request).getWebResponse().getContentAsString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,6 +161,9 @@ public class TestAnnotations {
|
||||||
-11
|
-11
|
||||||
defaultHeader2
|
defaultHeader2
|
||||||
-12
|
-12
|
||||||
|
propval1
|
||||||
|
defaultProp2
|
||||||
|
propval1
|
||||||
""", webClient.getPage(request).getWebResponse().getContentAsString());
|
""", webClient.getPage(request).getWebResponse().getContentAsString());
|
||||||
|
|
||||||
request.setRequestBody("836");
|
request.setRequestBody("836");
|
||||||
|
@ -189,6 +198,9 @@ public class TestAnnotations {
|
||||||
-11
|
-11
|
||||||
defaultHeader2
|
defaultHeader2
|
||||||
-12
|
-12
|
||||||
|
propval1
|
||||||
|
defaultProp2
|
||||||
|
propval1
|
||||||
""", webClient.getPage(request).getWebResponse().getContentAsString());
|
""", webClient.getPage(request).getWebResponse().getContentAsString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,6 +277,9 @@ public class TestAnnotations {
|
||||||
-11
|
-11
|
||||||
defaultHeader2
|
defaultHeader2
|
||||||
-12
|
-12
|
||||||
|
propval1
|
||||||
|
defaultProp2
|
||||||
|
propval1
|
||||||
""", page.getWebResponse().getContentAsString());
|
""", page.getWebResponse().getContentAsString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
603
lib/src/test/java/rife/ioc/TestHierarchicalProperties.java
Normal file
603
lib/src/test/java/rife/ioc/TestHierarchicalProperties.java
Normal file
|
@ -0,0 +1,603 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2001-2022 Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||||
|
*/
|
||||||
|
package rife.ioc;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import rife.ioc.exceptions.IncompatiblePropertyValueTypeException;
|
||||||
|
import rife.ioc.exceptions.PropertyValueException;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
public class TestHierarchicalProperties {
|
||||||
|
@Test
|
||||||
|
void testInstantiation() {
|
||||||
|
var properties = new HierarchicalProperties();
|
||||||
|
assertNotNull(properties);
|
||||||
|
assertEquals(0, properties.size());
|
||||||
|
assertNotNull(properties.getNames());
|
||||||
|
assertEquals(0, properties.getNames().size());
|
||||||
|
assertNotNull(properties.getInjectableNames());
|
||||||
|
assertEquals(0, properties.getInjectableNames().size());
|
||||||
|
assertNotNull(properties.getLocalMap());
|
||||||
|
assertEquals(0, properties.getLocalMap().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSingleInstance() {
|
||||||
|
Iterator<String> names_it;
|
||||||
|
|
||||||
|
PropertyValue property1 = new PropertyValueObject("value1");
|
||||||
|
PropertyValue property2 = new PropertyValueObject("value2");
|
||||||
|
PropertyValue property3 = new PropertyValueObject("value3");
|
||||||
|
PropertyValue property4 = new PropertyValueObject("value4");
|
||||||
|
PropertyValue property5 = new PropertyValueObject("value5");
|
||||||
|
|
||||||
|
var properties = new HierarchicalProperties();
|
||||||
|
assertSame(properties, properties.put("name1", property1));
|
||||||
|
assertSame(properties, properties.put("name2", property2));
|
||||||
|
assertSame(properties, properties.put("non.identifier.name3", property3));
|
||||||
|
assertEquals(3, properties.size());
|
||||||
|
assertNotNull(properties.getLocalMap());
|
||||||
|
assertEquals(3, properties.getLocalMap().size());
|
||||||
|
|
||||||
|
assertTrue(properties.contains("name1"));
|
||||||
|
assertTrue(properties.contains("name2"));
|
||||||
|
assertTrue(properties.contains("non.identifier.name3"));
|
||||||
|
|
||||||
|
assertSame(property1, properties.get("name1"));
|
||||||
|
assertSame(property2, properties.get("name2"));
|
||||||
|
assertSame(property3, properties.get("non.identifier.name3"));
|
||||||
|
assertEquals("value1", properties.getValue("name1"));
|
||||||
|
assertEquals("value2", properties.getValue("name2"));
|
||||||
|
assertEquals("value3", properties.getValue("non.identifier.name3"));
|
||||||
|
assertEquals("value1", properties.getValueString("name1"));
|
||||||
|
assertEquals("value2", properties.getValueString("name2"));
|
||||||
|
assertEquals("value3", properties.getValueString("non.identifier.name3"));
|
||||||
|
|
||||||
|
names_it = properties.getNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("non.identifier.name3", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
names_it = properties.getInjectableNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
assertSame(property2, properties.remove("name2"));
|
||||||
|
assertEquals(2, properties.size());
|
||||||
|
|
||||||
|
assertTrue(properties.contains("name1"));
|
||||||
|
assertFalse(properties.contains("name2"));
|
||||||
|
assertTrue(properties.contains("non.identifier.name3"));
|
||||||
|
|
||||||
|
names_it = properties.getNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("non.identifier.name3", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
names_it = properties.getInjectableNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
var properties_alternative = new HierarchicalProperties();
|
||||||
|
assertSame(properties_alternative, properties_alternative.put("name4", property4));
|
||||||
|
assertSame(properties_alternative, properties_alternative.put("non.identifier.name5", property5));
|
||||||
|
assertEquals(2, properties_alternative.size());
|
||||||
|
|
||||||
|
assertSame(properties, properties.putAll(properties_alternative));
|
||||||
|
|
||||||
|
assertEquals(4, properties.size());
|
||||||
|
|
||||||
|
assertTrue(properties.contains("name1"));
|
||||||
|
assertTrue(properties.contains("non.identifier.name3"));
|
||||||
|
assertTrue(properties.contains("name4"));
|
||||||
|
assertTrue(properties.contains("non.identifier.name5"));
|
||||||
|
|
||||||
|
assertSame(property1, properties.get("name1"));
|
||||||
|
assertSame(property3, properties.get("non.identifier.name3"));
|
||||||
|
assertSame(property4, properties.get("name4"));
|
||||||
|
assertSame(property5, properties.get("non.identifier.name5"));
|
||||||
|
assertEquals("value1", properties.getValue("name1"));
|
||||||
|
assertNull(properties.getValue("name2"));
|
||||||
|
var default_value = 34;
|
||||||
|
assertSame(default_value, properties.getValue("name2", default_value));
|
||||||
|
assertEquals("value3", properties.getValue("non.identifier.name3"));
|
||||||
|
assertEquals("value4", properties.getValue("name4"));
|
||||||
|
assertEquals("value5", properties.getValue("non.identifier.name5"));
|
||||||
|
assertEquals("value1", properties.getValueString("name1"));
|
||||||
|
assertNull(properties.getValueString("name2"));
|
||||||
|
assertEquals("somevalue", properties.getValueString("name2", "somevalue"));
|
||||||
|
assertEquals("value3", properties.getValueString("non.identifier.name3"));
|
||||||
|
assertEquals("value4", properties.getValueString("name4"));
|
||||||
|
assertEquals("value5", properties.getValueString("non.identifier.name5"));
|
||||||
|
|
||||||
|
names_it = properties.getNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("non.identifier.name3", names_it.next());
|
||||||
|
assertEquals("name4", names_it.next());
|
||||||
|
assertEquals("non.identifier.name5", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
names_it = properties.getInjectableNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name4", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testHierarchy() {
|
||||||
|
/*
|
||||||
|
* This is the hierarchy that's being built.
|
||||||
|
*
|
||||||
|
* grandparent
|
||||||
|
* -----------
|
||||||
|
* name1 (property1d)
|
||||||
|
* name2 (property2d)
|
||||||
|
* name2_grandparent (property2d)
|
||||||
|
* non.identifier.name3 (property3d)
|
||||||
|
* |
|
||||||
|
* ______________|___________________________
|
||||||
|
* / \
|
||||||
|
* / \
|
||||||
|
* parent1 parent2
|
||||||
|
* ------- -------
|
||||||
|
* name1 (property1c) name2 (property2c)
|
||||||
|
* name2_parent (property2c) non.identifier.name3_parent (property3c)
|
||||||
|
* | |
|
||||||
|
* ___________|___________________ |
|
||||||
|
* / \ |
|
||||||
|
* / \ |
|
||||||
|
* child1 child2 child3
|
||||||
|
* ------ ------ ------
|
||||||
|
* name1 (property1) name1 (property1b) non.identifier.name3 (property3b)
|
||||||
|
* name2 (property2) name2 (property2b)
|
||||||
|
* non.identifier.name3 (property3)
|
||||||
|
*/
|
||||||
|
Iterator<String> names_it;
|
||||||
|
|
||||||
|
PropertyValue property1 = new PropertyValueObject("value1");
|
||||||
|
PropertyValue property2 = new PropertyValueObject("value2");
|
||||||
|
PropertyValue property3 = new PropertyValueObject("value3");
|
||||||
|
PropertyValue property1b = new PropertyValueObject("value1b");
|
||||||
|
PropertyValue property2b = new PropertyValueObject("value2b");
|
||||||
|
PropertyValue property3b = new PropertyValueObject("value3b");
|
||||||
|
PropertyValue property1c = new PropertyValueObject("value1c");
|
||||||
|
PropertyValue property2c = new PropertyValueObject("value2c");
|
||||||
|
PropertyValue property3c = new PropertyValueObject("value3c");
|
||||||
|
PropertyValue property1d = new PropertyValueObject("value1d");
|
||||||
|
PropertyValue property2d = new PropertyValueObject("value2d");
|
||||||
|
PropertyValue property3d = new PropertyValueObject("value3d");
|
||||||
|
|
||||||
|
var properties_child1 = new HierarchicalProperties();
|
||||||
|
assertSame(properties_child1, properties_child1.put("name1", property1));
|
||||||
|
assertSame(properties_child1, properties_child1.put("name2", property2));
|
||||||
|
assertSame(properties_child1, properties_child1.put("non.identifier.name3", property3));
|
||||||
|
assertEquals(3, properties_child1.size());
|
||||||
|
assertSame(property1, properties_child1.get("name1"));
|
||||||
|
assertSame(property2, properties_child1.get("name2"));
|
||||||
|
assertSame(property3, properties_child1.get("non.identifier.name3"));
|
||||||
|
names_it = properties_child1.getNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("non.identifier.name3", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
names_it = properties_child1.getInjectableNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
var properties_child2 = new HierarchicalProperties();
|
||||||
|
assertSame(properties_child2, properties_child2.put("name1", property1b));
|
||||||
|
assertSame(properties_child2, properties_child2.put("name2", property2b));
|
||||||
|
assertEquals(2, properties_child2.size());
|
||||||
|
assertSame(property1b, properties_child2.get("name1"));
|
||||||
|
assertSame(property2b, properties_child2.get("name2"));
|
||||||
|
names_it = properties_child2.getNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
names_it = properties_child2.getInjectableNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
var properties_child3 = new HierarchicalProperties();
|
||||||
|
assertSame(properties_child3, properties_child3.put("non.identifier.name3", property3b));
|
||||||
|
assertEquals(1, properties_child3.size());
|
||||||
|
assertSame(property3b, properties_child3.get("non.identifier.name3"));
|
||||||
|
names_it = properties_child3.getNames().iterator();
|
||||||
|
assertEquals("non.identifier.name3", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
names_it = properties_child3.getInjectableNames().iterator();
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
var properties_parent1 = new HierarchicalProperties();
|
||||||
|
assertSame(properties_parent1, properties_parent1.put("name1", property1c));
|
||||||
|
assertSame(properties_parent1, properties_parent1.put("name2_parent", property2c));
|
||||||
|
assertEquals(2, properties_parent1.size());
|
||||||
|
assertSame(property1c, properties_parent1.get("name1"));
|
||||||
|
assertSame(property2c, properties_parent1.get("name2_parent"));
|
||||||
|
names_it = properties_parent1.getNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2_parent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
names_it = properties_parent1.getInjectableNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2_parent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
var properties_parent2 = new HierarchicalProperties();
|
||||||
|
assertSame(properties_parent2, properties_parent2.put("name2", property2c));
|
||||||
|
assertSame(properties_parent2, properties_parent2.put("non.identifier.name3_parent", property3c));
|
||||||
|
assertEquals(2, properties_parent2.size());
|
||||||
|
assertSame(property2c, properties_parent2.get("name2"));
|
||||||
|
assertSame(property3c, properties_parent2.get("non.identifier.name3_parent"));
|
||||||
|
names_it = properties_parent2.getNames().iterator();
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("non.identifier.name3_parent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
names_it = properties_parent2.getInjectableNames().iterator();
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
var properties_grandparent = new HierarchicalProperties();
|
||||||
|
assertSame(properties_grandparent, properties_grandparent.put("name1", property1d));
|
||||||
|
assertSame(properties_grandparent, properties_grandparent.put("name2", property2d));
|
||||||
|
assertSame(properties_grandparent, properties_grandparent.put("name2_grandparent", property2d));
|
||||||
|
assertSame(properties_grandparent, properties_grandparent.put("non.identifier.name3", property3d));
|
||||||
|
assertEquals(4, properties_grandparent.size());
|
||||||
|
assertSame(property1d, properties_grandparent.get("name1"));
|
||||||
|
assertSame(property2d, properties_grandparent.get("name2"));
|
||||||
|
assertSame(property2d, properties_grandparent.get("name2_grandparent"));
|
||||||
|
assertSame(property3d, properties_grandparent.get("non.identifier.name3"));
|
||||||
|
names_it = properties_grandparent.getNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("name2_grandparent", names_it.next());
|
||||||
|
assertEquals("non.identifier.name3", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
names_it = properties_grandparent.getInjectableNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("name2_grandparent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
// set the first level parents
|
||||||
|
properties_child1.parent(properties_parent1);
|
||||||
|
assertSame(properties_parent1, properties_child1.getRoot());
|
||||||
|
assertEquals(4, properties_child1.size());
|
||||||
|
assertSame(property1, properties_child1.get("name1"));
|
||||||
|
assertSame(property2, properties_child1.get("name2"));
|
||||||
|
assertSame(property2c, properties_child1.get("name2_parent"));
|
||||||
|
assertSame(property3, properties_child1.get("non.identifier.name3"));
|
||||||
|
names_it = properties_child1.getNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("non.identifier.name3", names_it.next());
|
||||||
|
assertEquals("name2_parent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
names_it = properties_child1.getInjectableNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("name2_parent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
properties_child2.parent(properties_parent1);
|
||||||
|
assertSame(properties_parent1, properties_child2.getRoot());
|
||||||
|
assertEquals(3, properties_child2.size());
|
||||||
|
assertSame(property1b, properties_child2.get("name1"));
|
||||||
|
assertSame(property2b, properties_child2.get("name2"));
|
||||||
|
names_it = properties_child2.getNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("name2_parent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
names_it = properties_child2.getInjectableNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("name2_parent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
properties_child3.parent(properties_parent2);
|
||||||
|
assertSame(properties_parent2, properties_child3.getRoot());
|
||||||
|
assertEquals(3, properties_child3.size());
|
||||||
|
assertSame(property3b, properties_child3.get("non.identifier.name3"));
|
||||||
|
assertSame(property2c, properties_child3.get("name2"));
|
||||||
|
assertSame(property3c, properties_child3.get("non.identifier.name3_parent"));
|
||||||
|
names_it = properties_child3.getNames().iterator();
|
||||||
|
assertEquals("non.identifier.name3", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("non.identifier.name3_parent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
names_it = properties_child3.getInjectableNames().iterator();
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
// set the second level parents
|
||||||
|
properties_parent1.parent(properties_grandparent);
|
||||||
|
assertEquals(5, properties_child1.size());
|
||||||
|
assertSame(property1, properties_child1.get("name1"));
|
||||||
|
assertSame(property2, properties_child1.get("name2"));
|
||||||
|
assertSame(property2c, properties_child1.get("name2_parent"));
|
||||||
|
assertSame(property3, properties_child1.get("non.identifier.name3"));
|
||||||
|
assertSame(property2d, properties_child1.get("name2_grandparent"));
|
||||||
|
names_it = properties_child1.getNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("non.identifier.name3", names_it.next());
|
||||||
|
assertEquals("name2_parent", names_it.next());
|
||||||
|
assertEquals("name2_grandparent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
names_it = properties_child1.getInjectableNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("name2_parent", names_it.next());
|
||||||
|
assertEquals("name2_grandparent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
properties_parent2.parent(properties_grandparent);
|
||||||
|
assertEquals(5, properties_child3.size());
|
||||||
|
assertSame(property3b, properties_child3.get("non.identifier.name3"));
|
||||||
|
assertSame(property2c, properties_child3.get("name2"));
|
||||||
|
assertSame(property3c, properties_child3.get("non.identifier.name3_parent"));
|
||||||
|
assertSame(property1d, properties_child3.get("name1"));
|
||||||
|
assertSame(property2d, properties_child3.get("name2_grandparent"));
|
||||||
|
names_it = properties_child3.getNames().iterator();
|
||||||
|
assertEquals("non.identifier.name3", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("non.identifier.name3_parent", names_it.next());
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2_grandparent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
names_it = properties_child3.getInjectableNames().iterator();
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2_grandparent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
assertSame(properties_grandparent, properties_child1.getRoot());
|
||||||
|
assertSame(properties_grandparent, properties_child2.getRoot());
|
||||||
|
assertSame(properties_grandparent, properties_child3.getRoot());
|
||||||
|
|
||||||
|
// manipulate the hierarchy
|
||||||
|
assertSame(property1, properties_child1.remove("name1"));
|
||||||
|
assertNull(properties_child1.remove("name1"));
|
||||||
|
assertSame(property1c, properties_child1.get("name1"));
|
||||||
|
|
||||||
|
assertSame(property2c, properties_parent1.remove("name2_parent"));
|
||||||
|
assertNull(properties_parent1.remove("name2_parent"));
|
||||||
|
assertNull(properties_parent1.get("name2_parent"));
|
||||||
|
|
||||||
|
assertSame(property1c, properties_parent1.remove("name1"));
|
||||||
|
assertNull(properties_child1.remove("name1"));
|
||||||
|
assertSame(property1d, properties_child1.get("name1"));
|
||||||
|
assertSame(property1d, properties_parent1.get("name1"));
|
||||||
|
|
||||||
|
assertSame(property3b, properties_child3.remove("non.identifier.name3"));
|
||||||
|
assertNull(properties_child3.remove("non.identifier.name3"));
|
||||||
|
assertSame(property3d, properties_child3.get("non.identifier.name3"));
|
||||||
|
|
||||||
|
assertSame(property2c, properties_parent2.remove("name2"));
|
||||||
|
assertNull(properties_parent2.remove("name2"));
|
||||||
|
assertSame(property2d, properties_child3.get("name2"));
|
||||||
|
|
||||||
|
assertSame(property2d, properties_grandparent.remove("name2"));
|
||||||
|
assertNull(properties_grandparent.remove("name2"));
|
||||||
|
assertNull(properties_child3.get("name2"));
|
||||||
|
|
||||||
|
names_it = properties_child1.getNames().iterator();
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("non.identifier.name3", names_it.next());
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2_grandparent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
names_it = properties_child1.getInjectableNames().iterator();
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2_grandparent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
names_it = properties_child2.getNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("name2_grandparent", names_it.next());
|
||||||
|
assertEquals("non.identifier.name3", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
names_it = properties_child2.getInjectableNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("name2_grandparent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
names_it = properties_child3.getNames().iterator();
|
||||||
|
assertEquals("non.identifier.name3_parent", names_it.next());
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2_grandparent", names_it.next());
|
||||||
|
assertEquals("non.identifier.name3", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
names_it = properties_child3.getInjectableNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2_grandparent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
PropertyValue property2e = new PropertyValueObject("value1e");
|
||||||
|
assertSame(properties_parent1, properties_parent1.put("new_name2", property2e));
|
||||||
|
PropertyValue property3e = new PropertyValueObject("value3e");
|
||||||
|
assertSame(properties_grandparent, properties_grandparent.put("new_non.identifier.name3", property3e));
|
||||||
|
|
||||||
|
names_it = properties_child1.getNames().iterator();
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("non.identifier.name3", names_it.next());
|
||||||
|
assertEquals("new_name2", names_it.next());
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2_grandparent", names_it.next());
|
||||||
|
assertEquals("new_non.identifier.name3", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
names_it = properties_child1.getInjectableNames().iterator();
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("new_name2", names_it.next());
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2_grandparent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
names_it = properties_child2.getNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("new_name2", names_it.next());
|
||||||
|
assertEquals("name2_grandparent", names_it.next());
|
||||||
|
assertEquals("non.identifier.name3", names_it.next());
|
||||||
|
assertEquals("new_non.identifier.name3", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
names_it = properties_child2.getInjectableNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2", names_it.next());
|
||||||
|
assertEquals("new_name2", names_it.next());
|
||||||
|
assertEquals("name2_grandparent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
|
||||||
|
names_it = properties_child3.getNames().iterator();
|
||||||
|
assertEquals("non.identifier.name3_parent", names_it.next());
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2_grandparent", names_it.next());
|
||||||
|
assertEquals("non.identifier.name3", names_it.next());
|
||||||
|
assertEquals("new_non.identifier.name3", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
names_it = properties_child3.getInjectableNames().iterator();
|
||||||
|
assertEquals("name1", names_it.next());
|
||||||
|
assertEquals("name2_grandparent", names_it.next());
|
||||||
|
assertFalse(names_it.hasNext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPutAll() {
|
||||||
|
var properties1 = new HierarchicalProperties();
|
||||||
|
assertEquals(0, properties1.size());
|
||||||
|
var properties2 = new HierarchicalProperties();
|
||||||
|
assertEquals(0, properties2.size());
|
||||||
|
|
||||||
|
Object value1 = new StringBuffer("test");
|
||||||
|
Object value2 = new Date();
|
||||||
|
properties2.put("24", value1);
|
||||||
|
properties2.put("test", value2);
|
||||||
|
properties1.putAll(properties2);
|
||||||
|
|
||||||
|
assertEquals(2, properties1.size());
|
||||||
|
Iterator<String> names_it = properties1.getNames().iterator();
|
||||||
|
assertEquals("24", names_it.next());
|
||||||
|
assertEquals("test", names_it.next());
|
||||||
|
assertSame(value1, properties1.get("24").getValue());
|
||||||
|
assertSame(value2, properties1.get("test").getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPutAllMap() {
|
||||||
|
var properties = new HierarchicalProperties();
|
||||||
|
assertEquals(0, properties.size());
|
||||||
|
|
||||||
|
Map<Object, Object> map = new LinkedHashMap<>();
|
||||||
|
Object value1 = new StringBuffer("test");
|
||||||
|
Object value2 = new Date();
|
||||||
|
map.put(24, value1);
|
||||||
|
map.put("test", value2);
|
||||||
|
properties.putAll(map);
|
||||||
|
|
||||||
|
assertEquals(2, properties.size());
|
||||||
|
Iterator<String> names_it = properties.getNames().iterator();
|
||||||
|
assertEquals("24", names_it.next());
|
||||||
|
assertEquals("test", names_it.next());
|
||||||
|
assertSame(value1, properties.get("24").getValue());
|
||||||
|
assertSame(value2, properties.get("test").getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPutAllWithoutReplacing() {
|
||||||
|
var properties1 = new HierarchicalProperties();
|
||||||
|
assertEquals(0, properties1.size());
|
||||||
|
var properties2 = new HierarchicalProperties();
|
||||||
|
assertEquals(0, properties2.size());
|
||||||
|
|
||||||
|
Object value1 = new StringBuffer("test");
|
||||||
|
Object value2 = new Date();
|
||||||
|
Object value3 = 38746387L;
|
||||||
|
properties1.put("test", value2);
|
||||||
|
properties2.put("24", value1);
|
||||||
|
properties2.put("test", value3);
|
||||||
|
properties1.putAllWithoutReplacing(properties2);
|
||||||
|
|
||||||
|
assertEquals(2, properties1.size());
|
||||||
|
Iterator<String> names_it = properties1.getNames().iterator();
|
||||||
|
assertEquals("test", names_it.next());
|
||||||
|
assertEquals("24", names_it.next());
|
||||||
|
assertSame(value1, properties1.get("24").getValue());
|
||||||
|
assertSame(value2, properties1.get("test").getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetValueString() {
|
||||||
|
var properties = new HierarchicalProperties();
|
||||||
|
Object value1 = new StringBuffer("test");
|
||||||
|
Object value2 = new BigDecimal("12682861E+10");
|
||||||
|
properties.put("value1", value1);
|
||||||
|
properties.put("value2", value2);
|
||||||
|
properties.put("value3", null);
|
||||||
|
properties.put("value4", "");
|
||||||
|
|
||||||
|
assertEquals("test", properties.getValueString("value1"));
|
||||||
|
assertEquals("1.2682861E+17", properties.getValueString("value2"));
|
||||||
|
assertNull(properties.getValueString("value3"));
|
||||||
|
assertNull(properties.getValueString("value4"));
|
||||||
|
assertNull(properties.getValueString("inexistent"));
|
||||||
|
|
||||||
|
assertEquals("test", properties.getValueString("value1", "default1"));
|
||||||
|
assertEquals("1.2682861E+17", properties.getValueString("value2", "default2"));
|
||||||
|
assertEquals("default3", properties.getValueString("value3", "default3"));
|
||||||
|
assertEquals("default4", properties.getValueString("value4", "default4"));
|
||||||
|
assertEquals("default5", properties.getValueString("inexistent", "default5"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetValueTyped() {
|
||||||
|
var properties = new HierarchicalProperties();
|
||||||
|
Object value1 = new StringBuffer("test");
|
||||||
|
Object value2 = new BigDecimal("12682861E+10");
|
||||||
|
Object value4 = "";
|
||||||
|
properties.put("value1", value1);
|
||||||
|
properties.put("value2", value2);
|
||||||
|
properties.put("value3", null);
|
||||||
|
properties.put("value4", value4);
|
||||||
|
|
||||||
|
assertSame(value1, properties.getValueTyped("value1", StringBuffer.class));
|
||||||
|
assertSame(value2, properties.getValueTyped("value2", BigDecimal.class));
|
||||||
|
assertNull(properties.getValueTyped("value3", String.class));
|
||||||
|
assertSame(value4, properties.getValueTyped("value4", String.class));
|
||||||
|
assertNull(properties.getValueTyped("inexistent", String.class));
|
||||||
|
|
||||||
|
var default3 = new BigDecimal("5718620E+6");
|
||||||
|
Integer default5 = 97586;
|
||||||
|
assertSame(value1, properties.getValueTyped("value1", StringBuffer.class, new StringBuffer("default1")));
|
||||||
|
assertSame(value2, properties.getValueTyped("value2", BigDecimal.class, new BigDecimal(1268)));
|
||||||
|
assertSame(default3, properties.getValueTyped("value3", BigDecimal.class, default3));
|
||||||
|
assertSame(value4, properties.getValueTyped("value4", String.class, "default4"));
|
||||||
|
assertSame(default5, properties.getValueTyped("inexistent", Integer.class, default5));
|
||||||
|
|
||||||
|
try {
|
||||||
|
properties.getValueTyped("value2", Date.class);
|
||||||
|
fail("Expected exception");
|
||||||
|
} catch (PropertyValueException e) {
|
||||||
|
assertTrue(e instanceof IncompatiblePropertyValueTypeException);
|
||||||
|
assertEquals("value2", ((IncompatiblePropertyValueTypeException) e).getPropertyName());
|
||||||
|
assertSame(Date.class, ((IncompatiblePropertyValueTypeException) e).getExpectedType());
|
||||||
|
assertSame(BigDecimal.class, ((IncompatiblePropertyValueTypeException) e).getActualType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
lib/src/test/java/rife/ioc/TestPropertyValueList.java
Normal file
54
lib/src/test/java/rife/ioc/TestPropertyValueList.java
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2001-2022 Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||||
|
*/
|
||||||
|
package rife.ioc;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
public class TestPropertyValueList {
|
||||||
|
@Test
|
||||||
|
void testInstantiation() {
|
||||||
|
PropertyValueList list = new PropertyValueList();
|
||||||
|
assertNotNull(list);
|
||||||
|
assertEquals(0, list.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSingleNonNegligible() {
|
||||||
|
var list = new PropertyValueList();
|
||||||
|
var value = new PropertyValueObject("Not Negligible");
|
||||||
|
list.add(value);
|
||||||
|
assertEquals(1, list.size());
|
||||||
|
assertSame(value, list.makePropertyValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testOneNoneNegligibleOtherNegligibles() {
|
||||||
|
var value = new PropertyValueObject("Not Negligible");
|
||||||
|
var list = new PropertyValueList();
|
||||||
|
list.add(new PropertyValueObject(" "));
|
||||||
|
list.add(value);
|
||||||
|
list.add(new PropertyValueObject(" "));
|
||||||
|
list.add(new PropertyValueObject(""));
|
||||||
|
assertEquals(4, list.size());
|
||||||
|
assertSame(value, list.makePropertyValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testOneNoneNegligibleOtherNonNegligible() {
|
||||||
|
var value = new PropertyValueObject("Not Negligible");
|
||||||
|
var list = new PropertyValueList();
|
||||||
|
list.add(new PropertyValueObject(" "));
|
||||||
|
list.add(value);
|
||||||
|
list.add(new PropertyValueObject(" "));
|
||||||
|
list.add(new PropertyValueObject("testing"));
|
||||||
|
assertEquals(4, list.size());
|
||||||
|
|
||||||
|
PropertyValue result = list.makePropertyValue();
|
||||||
|
assertNotSame(value, result);
|
||||||
|
assertEquals(value + " testing", result.getValueString());
|
||||||
|
}
|
||||||
|
}
|
52
lib/src/test/java/rife/ioc/TestPropertyValueObject.java
Normal file
52
lib/src/test/java/rife/ioc/TestPropertyValueObject.java
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2001-2022 Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||||
|
*/
|
||||||
|
package rife.ioc;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
public class TestPropertyValueObject {
|
||||||
|
@Test
|
||||||
|
void testInstantiation() {
|
||||||
|
Integer value = 25;
|
||||||
|
|
||||||
|
var object = new PropertyValueObject(value);
|
||||||
|
assertNotNull(object);
|
||||||
|
assertTrue(object.isStatic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetValue() {
|
||||||
|
Integer value = 25;
|
||||||
|
|
||||||
|
var object = new PropertyValueObject(value);
|
||||||
|
assertSame(value, object.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetValueString() {
|
||||||
|
Integer value = 25;
|
||||||
|
|
||||||
|
var object = new PropertyValueObject(value);
|
||||||
|
assertEquals("25", object.getValueString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testToString() {
|
||||||
|
Integer value = 25;
|
||||||
|
|
||||||
|
var object = new PropertyValueObject(value);
|
||||||
|
assertEquals("25", object.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testisNegligible() {
|
||||||
|
assertFalse(new PropertyValueObject("lhkjkj").isNegligible());
|
||||||
|
assertTrue(new PropertyValueObject(" ").isNegligible());
|
||||||
|
assertTrue(new PropertyValueObject("").isNegligible());
|
||||||
|
assertTrue(new PropertyValueObject(null).isNegligible());
|
||||||
|
}
|
||||||
|
}
|
67
lib/src/test/java/rife/ioc/TestPropertyValueTemplate.java
Normal file
67
lib/src/test/java/rife/ioc/TestPropertyValueTemplate.java
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2001-2022 Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||||
|
*/
|
||||||
|
package rife.ioc;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import rife.ioc.exceptions.TemplateFactoryUnknownException;
|
||||||
|
import rife.template.Template;
|
||||||
|
import rife.template.exceptions.TemplateNotFoundException;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
public class TestPropertyValueTemplate {
|
||||||
|
@Test
|
||||||
|
void testInstantiation() {
|
||||||
|
PropertyValueTemplate object = new PropertyValueTemplate("html", "values");
|
||||||
|
assertNotNull(object);
|
||||||
|
assertFalse(object.isStatic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetValue() {
|
||||||
|
PropertyValueTemplate object = new PropertyValueTemplate("html", "values");
|
||||||
|
assertNotNull(object.getValue());
|
||||||
|
assertTrue(object.getValue() instanceof Template);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetValueUnknownFactory() {
|
||||||
|
PropertyValueTemplate object = new PropertyValueTemplate("blah", "values");
|
||||||
|
try {
|
||||||
|
object.getValue();
|
||||||
|
fail("TemplateFactoryUnknownException wasn't thrown");
|
||||||
|
} catch (TemplateFactoryUnknownException e) {
|
||||||
|
assertEquals("blah", e.getType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetValueUnknownTemplate() {
|
||||||
|
PropertyValueTemplate object = new PropertyValueTemplate("html", "blahblihbloh");
|
||||||
|
try {
|
||||||
|
object.getValue();
|
||||||
|
fail("template 'blahblihbloh' shouldn't have been found");
|
||||||
|
} catch (TemplateNotFoundException e) {
|
||||||
|
assertEquals("blahblihbloh", e.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetValueString() {
|
||||||
|
PropertyValueTemplate object = new PropertyValueTemplate("html", "values");
|
||||||
|
assertEquals("{{v VALUE1/}}<!--v VALUE2/-->{{v VALUE3/}}\n", object.getValueString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testToString() {
|
||||||
|
PropertyValueTemplate object = new PropertyValueTemplate("html", "values");
|
||||||
|
assertEquals("{{v VALUE1/}}<!--v VALUE2/-->{{v VALUE3/}}\n", object.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testisNegligible() {
|
||||||
|
assertFalse(new PropertyValueTemplate("html", "values").isNegligible());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue