Nuiton-utils-commits
Threads by month
- ----- 2026 -----
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- 3157 discussions
r2155 - in trunk: nuiton-utils nuiton-utils/src/main/java/org/nuiton/util nuiton-utils/src/main/java/org/nuiton/util/decorator nuiton-utils/src/test/java/org/nuiton/util nuiton-utils/src/test/java/org/nuiton/util/decorator nuiton-validator/src/license
by tchemit@users.nuiton.org 31 Jul '11
by tchemit@users.nuiton.org 31 Jul '11
31 Jul '11
Author: tchemit
Date: 2011-07-31 15:25:21 +0200 (Sun, 31 Jul 2011)
New Revision: 2155
Url: http://nuiton.org/repositories/revision/nuiton-utils/2155
Log:
Evolution #1594: Update xwork to 2.2.3 (update third-parties)
Evolution #1643: New decorator api (from jaxx-runtime project)
updates svn properties
Added:
trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/
trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/Decorator.java
trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/DecoratorProvider.java
trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/DecoratorUtils.java
trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/JXPathDecorator.java
trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/MapPropertyHandler.java
trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/MultiJXPathDecorator.java
trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/PropertyDecorator.java
trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/
trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/Data.java
trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/DecoratorProviderTest.java
trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/JXPathContextTester.java
trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/JXPathDecoratorTest.java
trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/MapPropertyHandlerTest.java
trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/MultiJXPathDecoratorTest.java
Modified:
trunk/nuiton-utils/pom.xml
trunk/nuiton-utils/src/main/java/org/nuiton/util/MatrixMap.java
trunk/nuiton-utils/src/test/java/org/nuiton/util/MatrixMapTest.java
trunk/nuiton-validator/src/license/THIRD-PARTY.properties
Modified: trunk/nuiton-utils/pom.xml
===================================================================
--- trunk/nuiton-utils/pom.xml 2011-07-19 16:46:06 UTC (rev 2154)
+++ trunk/nuiton-utils/pom.xml 2011-07-31 13:25:21 UTC (rev 2155)
@@ -66,6 +66,11 @@
</dependency>
<dependency>
+ <groupId>commons-jxpath</groupId>
+ <artifactId>commons-jxpath</artifactId>
+ </dependency>
+
+ <dependency>
<groupId>org.nuiton.i18n</groupId>
<artifactId>nuiton-i18n</artifactId>
</dependency>
Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/MatrixMap.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/MatrixMap.java 2011-07-19 16:46:06 UTC (rev 2154)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/MatrixMap.java 2011-07-31 13:25:21 UTC (rev 2155)
@@ -1,3 +1,27 @@
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Utils
+ *
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2004 - 2011 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
package org.nuiton.util;
import java.io.Serializable;
Property changes on: trunk/nuiton-utils/src/main/java/org/nuiton/util/MatrixMap.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/Decorator.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/Decorator.java (rev 0)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/Decorator.java 2011-07-31 13:25:21 UTC (rev 2155)
@@ -0,0 +1,59 @@
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Utils
+ *
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2004 - 2011 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+package org.nuiton.util.decorator;
+
+import java.io.Serializable;
+
+/**
+ * A simple contract to define a String decorator on any java object.
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @param <O> the type of data to decorate
+ * @since 2.2.1
+ */
+public abstract class Decorator<O> implements Serializable {
+
+ private static final long serialVersionUID = -1L;
+
+ /** Type of the data to decorate */
+ protected final Class<O> internalClass;
+
+ public Decorator(Class<O> internalClass) throws NullPointerException {
+ if (internalClass == null) {
+ throw new NullPointerException("internalClass can not be null.");
+ }
+ this.internalClass = internalClass;
+ }
+
+ /**
+ * @param bean the bean to decorate
+ * @return the string value of the given bean
+ */
+ public abstract String toString(Object bean);
+
+ public Class<O> getInternalClass() {
+ return internalClass;
+ }
+}
Property changes on: trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/Decorator.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/DecoratorProvider.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/DecoratorProvider.java (rev 0)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/DecoratorProvider.java 2011-07-31 13:25:21 UTC (rev 2155)
@@ -0,0 +1,269 @@
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Utils
+ *
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2004 - 2011 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+package org.nuiton.util.decorator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A decorator provider.
+ * <p/>
+ * Implements the method {@link #loadDecorators()} to fill the decorators
+ * availables.
+ * <p/>
+ * Then can obtain decorator via the methods {@code getDecorator(...)}
+ * <p/>
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.2.1
+ */
+public abstract class DecoratorProvider {
+
+ /** Logger */
+ private static final Log log = LogFactory.getLog(JXPathDecorator.class);
+
+ /** Registred decorators. */
+ protected List<DecoratorContext<?>> decorators;
+
+ public DecoratorProvider() {
+ loadDecorators();
+ }
+
+ /** Load all decorators of the provider */
+ protected abstract void loadDecorators();
+
+ /**
+ * Obtain a decorator for the given object.
+ *
+ * @param object object of decorated object
+ * @param <O> object of decorated object
+ * @return the decorator or {@code null} if not found
+ */
+ @SuppressWarnings({"unchecked"})
+ public <O> Decorator<O> getDecorator(O object) {
+ return getDecorator(object, null);
+ }
+
+ /**
+ * Obtain a decorator given a object and an extra name to qualify the
+ * context.
+ *
+ * @param object object of decorated object
+ * @param name extra name to qualify the decorator to use
+ * @param <O> object of decorated object
+ * @return the decorator or {@code null} if not found
+ */
+ @SuppressWarnings({"unchecked"})
+ public <O> Decorator<O> getDecorator(O object, String name) {
+ Class<O> k = (Class<O>) object.getClass();
+ return getDecorator(k, name);
+ }
+
+ /**
+ * Obtain a decorator given a type.
+ *
+ * @param type type of decorated object
+ * @param <O> type of decorated object
+ * @return the decorator or {@code null} if not found
+ */
+ public <O> Decorator<O> getDecorator(Class<O> type) {
+ return getDecorator(type, null);
+ }
+
+ /**
+ * Obtain a decorator given a type and a extra name.
+ *
+ * @param type type of decorated object
+ * @param name extra name to qualify the decorator to use
+ * @param <O> type of decorated object
+ * @return the decorator or {@code null} if not found
+ */
+ public <O> Decorator<O> getDecorator(Class<O> type, String name) {
+ DecoratorContext<O> d = getDecoratorContext(type, name);
+ return d == null ? null : d.getDecorator();
+ }
+
+ public void reload() {
+ clear();
+ loadDecorators();
+ }
+
+ public void clear() {
+ if (decorators != null) {
+ decorators.clear();
+ }
+ }
+
+ protected void registerPropertyDecorator(Class<?> klass,
+ String expression) {
+ registerPropertyDecorator(klass, null, expression);
+ }
+
+ protected void registerJXPathDecorator(Class<?> klass, String expression) {
+ registerJXPathDecorator(klass, null, expression);
+ }
+
+ protected void registerMultiJXPathDecorator(Class<?> klass,
+ String expression,
+ String separator,
+ String separatorReplacement) {
+ registerMultiJXPathDecorator(klass, null, expression, separator,
+ separatorReplacement);
+ }
+
+ protected void registerPropertyDecorator(Class<?> klass,
+ String name,
+ String expression) {
+ Decorator<?> decorator =
+ DecoratorUtils.newPropertyDecorator(klass, expression);
+ registerDecorator(name, decorator);
+ }
+
+ protected void registerJXPathDecorator(Class<?> klass,
+ String name,
+ String expression) {
+ Decorator<?> decorator =
+ DecoratorUtils.newJXPathDecorator(klass, expression);
+ registerDecorator(name, decorator);
+ }
+
+ protected void registerMultiJXPathDecorator(Class<?> klass,
+ String name,
+ String expression,
+ String separator,
+ String separatorReplacement) {
+ Decorator<?> decorator = DecoratorUtils.newMultiJXPathDecorator(
+ klass, expression, separator, separatorReplacement
+ );
+ registerDecorator(name, decorator);
+ }
+
+ protected void registerDecorator(Decorator<?> decorator) {
+ registerDecorator(null, decorator);
+ }
+
+ /**
+ * Register a new decorator in the cache of the provider.
+ *
+ * @param <T> type of data decorated
+ * @param context the name decorator
+ * @param decorator the decorator to register
+ */
+ protected <T> void registerDecorator(String context,
+ Decorator<T> decorator) {
+
+ // obtain the decorator context
+ DecoratorContext<?> result =
+ getDecoratorContext(decorator.getInternalClass(), context);
+
+ if (result != null) {
+ throw new IllegalArgumentException(
+ "there is an already register decorator with context " +
+ result);
+ }
+
+ DecoratorContext<T> decoratorContext =
+ new DecoratorContext<T>(context, decorator);
+ if (log.isDebugEnabled()) {
+ log.debug(decoratorContext);
+ }
+ getDecorators().add(decoratorContext);
+ }
+
+ protected List<DecoratorContext<?>> getDecorators() {
+ if (decorators == null) {
+ decorators = new ArrayList<DecoratorContext<?>>();
+ }
+ return decorators;
+ }
+
+ @SuppressWarnings({"unchecked"})
+ protected <T> DecoratorContext<T> getDecoratorContext(Class<T> type,
+ String context) {
+ DecoratorContext<T> result = null;
+ if (decorators != null) {
+ for (DecoratorContext<?> d : decorators) {
+ if (type == null) {
+ if (d.accept(context)) {
+ result = (DecoratorContext<T>) d;
+ break;
+ }
+ continue;
+ }
+ if (d.accept(type, context)) {
+ result = (DecoratorContext<T>) d;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ public static class DecoratorContext<T> {
+
+ /** the context name of the decorator */
+ final String context;
+
+ /** the decorator */
+ final Decorator<T> decorator;
+
+ public DecoratorContext(String context, Decorator<T> decorator) {
+ this.context = context;
+ this.decorator = decorator;
+ }
+
+ public String getContext() {
+ return context;
+ }
+
+ public Decorator<T> getDecorator() {
+ return decorator;
+ }
+
+ public Class<T> getType() {
+ return decorator.getInternalClass();
+ }
+
+ public boolean accept(Class<?> type, String context) {
+ boolean accept = getType().isAssignableFrom(type) && accept(context);
+ return accept;
+ }
+
+ public boolean accept(String context) {
+ return this.context == null && context == null ||
+ this.context != null && this.context.equals(context);
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + "<type: " + getType().getName() +
+ ", context :" + context + ">";
+ }
+ }
+
+}
Property changes on: trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/DecoratorProvider.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/DecoratorUtils.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/DecoratorUtils.java (rev 0)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/DecoratorUtils.java 2011-07-31 13:25:21 UTC (rev 2155)
@@ -0,0 +1,300 @@
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Utils
+ *
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2004 - 2011 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+package org.nuiton.util.decorator;
+
+import org.nuiton.util.decorator.JXPathDecorator.Context;
+import org.nuiton.util.decorator.JXPathDecorator.JXPathComparator;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Some usefull methods on {@link Decorator} to create, and sort data with
+ * decorators.
+ * <p/>
+ * To create a new decorator, use one of the methods : <ul> <li>{@link
+ * #newPropertyDecorator(Class, String)}</li> <li>{@link
+ * #newJXPathDecorator(Class, String)}</li> <li>
+ * {@link #newMultiJXPathDecorator(Class, String, String)})</li>
+ * <li>{@link #newMultiJXPathDecorator(Class, String,String, String)})</li>
+ * </ul>
+ * <p/>
+ * To sort a list of data, using a {@link JXPathDecorator}, use the method
+ * {@link #sort(JXPathDecorator, List, int)}.
+ * <p/>
+ *
+ * @author tchemit <chemit(a)codelutiln.com>
+ * @since 2.2.1
+ */
+public class DecoratorUtils {
+
+ /** Logger */
+ private static final Log log = LogFactory.getLog(DecoratorUtils.class);
+
+
+ /**
+ * Factory method to instanciate a new {@link PropertyDecorator} for the
+ * given class {@code internlaClass} and a readable property name.
+ *
+ * @param internalClass the class of the objects decorated by the new
+ * decorator
+ * @param property the property
+ * @param <O> the generic type of class to be decorated by the new
+ * decorator
+ * @return the new instanciated decorator
+ * @throws IllegalArgumentException if the expression is not valid, says:
+ * <p/>
+ * - a missing right brace was detected.
+ * <p/>
+ * - a ${ was found in a jxpath token.
+ * @throws NullPointerException if internalClass parameter is null.
+ */
+ public static <O> PropertyDecorator<O> newPropertyDecorator(
+ Class<O> internalClass,
+ String property)
+ throws IllegalArgumentException, NullPointerException {
+ return new PropertyDecorator<O>(internalClass, property);
+ }
+
+ /**
+ * Factory method to instanciate a new {@link JXPathDecorator} for the given
+ * class {@code internalClass} and expression.
+ *
+ * @param internalClass the class of the objects decorated by the new
+ * decorator
+ * @param expression the expression to use to decorated objects
+ * @param <O> the generic type of class to be decorated by the new
+ * decorator
+ * @return the new instanciated decorator
+ * @throws IllegalArgumentException if the expression is not valid, says:
+ * <p/>
+ * - a missing right brace was detected.
+ * <p/>
+ * - a ${ was found in a jxpath token.
+ * @throws NullPointerException if internalClass parameter is null.
+ */
+ public static <O> JXPathDecorator<O> newJXPathDecorator(
+ Class<O> internalClass,
+ String expression)
+ throws IllegalArgumentException, NullPointerException {
+
+ Context<O> context = createJXPathContext(expression);
+ return new JXPathDecorator<O>(internalClass, expression, context);
+ }
+
+ public static <O> MultiJXPathDecorator<O> newMultiJXPathDecorator(
+ Class<O> internalClass,
+ String expression,
+ String separator)
+ throws IllegalArgumentException, NullPointerException {
+
+ MultiJXPathDecorator<O> decorator = newMultiJXPathDecorator(
+ internalClass,
+ expression,
+ separator,
+ separator);
+ return decorator;
+ }
+
+ public static <O> MultiJXPathDecorator<O> newMultiJXPathDecorator(
+ Class<O> internalClass,
+ String expression,
+ String separator,
+ String separatorReplacement)
+ throws IllegalArgumentException, NullPointerException {
+
+ Context<O>[] contexts = createMultiJXPathContext(
+ expression,
+ separator,
+ separatorReplacement);
+
+ return new MultiJXPathDecorator<O>(
+ internalClass,
+ expression,
+ separator,
+ separatorReplacement,
+ contexts);
+ }
+
+ /**
+ * Sort a list of data based on the first token property of a given context
+ * in a given decorator.
+ *
+ * @param <O> type of data to sort
+ * @param decorator the decorator to use to sort
+ * @param datas the list of data to sort
+ * @param pos the index of context to used in decorator to obtain
+ * sorted property.
+ */
+ public static <O> void sort(JXPathDecorator<O> decorator,
+ List<O> datas,
+ int pos) {
+ sort(decorator, datas, pos, false);
+ }
+
+ /**
+ * Sort a list of data based on the first token property of a given context
+ * in a given decorator.
+ *
+ * @param <O> type of data to sort
+ * @param decorator the decorator to use to sort
+ * @param datas the list of data to sort
+ * @param pos the index of context to used in decorator to obtain
+ * sorted property.
+ * @param reverse flag to sort in reverse order if sets to {@code true}
+ * @since 2.2
+ */
+ public static <O> void sort(JXPathDecorator<O> decorator,
+ List<O> datas,
+ int pos,
+ boolean reverse) {
+ Comparator<O> c = null;
+ boolean cachedComparator = false;
+ try {
+ c = decorator.getComparator(pos);
+ cachedComparator = c instanceof JXPathComparator<?>;
+
+ if (cachedComparator) {
+ ((JXPathComparator<O>) c).init(decorator, datas);
+ }
+ Collections.sort(datas, c);
+ if (reverse) {
+
+ // reverse order
+ Collections.reverse(datas);
+ }
+ } finally {
+ if (cachedComparator) {
+ ((JXPathComparator<?>) c).clear();
+ }
+ }
+ }
+
+ public static <O> Context<O> createJXPathContext(String expression) {
+ List<String> lTokens = new ArrayList<String>();
+ StringBuilder buffer = new StringBuilder();
+ int size = expression.length();
+ int end = -1;
+ int start;
+ while ((start = expression.indexOf("${", end + 1)) > -1) {
+ if (start > end + 1) {
+
+ // prefix of next jxpath token
+ buffer.append(expression.substring(end + 1, start));
+ }
+
+ // seek end of jxpath
+ end = expression.indexOf("}", start + 1);
+ if (end == -1) {
+ throw new IllegalArgumentException(
+ "could not find the rigth brace starting at car " +
+ start + " : " + expression.substring(start + 2));
+ }
+ String jxpath = expression.substring(start + 2, end);
+
+ // not allowed ${ inside a jxpath token
+ if (jxpath.contains("${")) {
+ throw new IllegalArgumentException(
+ "could not find a ${ inside a jxpath expression at " +
+ "car " + (start + 2) + " : " + jxpath);
+ }
+
+ // save the jxpath token
+ lTokens.add(jxpath);
+
+ // replace jxpath token in expresion with a string format variable
+ buffer.append('%').append(lTokens.size());
+ }
+ if (size > end + 1) {
+
+ // suffix after end jxpath (or all expression if no jxpath)
+ buffer.append(expression.substring(end + 1));
+ }
+ String[] tokens = lTokens.toArray(new String[lTokens.size()]);
+ return new Context<O>(buffer.toString(), tokens);
+ }
+
+ public static <O> Context<O>[] createMultiJXPathContext(
+ String expression,
+ String separator,
+ String separatorReplacement) {
+ int sep = expression.indexOf(separator);
+ if (sep == -1) {
+ Context<O>[] result = newInstance(1);
+ result[0] = createJXPathContext(expression);
+ return result;
+ }
+
+ List<String> tokens = new ArrayList<String>();
+ StringTokenizer stk = new StringTokenizer(expression, separator);
+ while (stk.hasMoreTokens()) {
+ tokens.add(stk.nextToken());
+ }
+
+ int nbTokens = tokens.size();
+ Context<O>[] contexts = newInstance(nbTokens);
+ if (log.isDebugEnabled()) {
+ log.debug("Will prepare " + nbTokens + " contexts from [" + expression + "]");
+ }
+ for (int i = 0; i < nbTokens; i++) {
+ StringBuilder buffer = new StringBuilder(expression.length());
+ for (int j = 0; j < nbTokens; j++) {
+ int index = (i + j) % nbTokens;
+ String str = tokens.get(index);
+
+ //replace all '%(index+1)$' pattern with '%(j+1)$'
+ Pattern p = Pattern.compile("\\%(" + (index + 1) + ")\\$");
+ Matcher matcher = p.matcher(str);
+ String safeStr = matcher.replaceAll("\\%" + (j + 1) + "\\$");
+
+ if (log.isDebugEnabled()) {
+ log.debug("[" + (index + 1) + "-->" + (j + 1) + "] " + str +
+ " transformed to " + safeStr);
+ }
+ buffer.append(separatorReplacement).append(safeStr);
+ }
+ String expr = buffer.substring(separatorReplacement.length());
+ if (log.isDebugEnabled()) {
+ log.debug("context [" + i + "] : " + expr);
+ }
+ contexts[i] = createJXPathContext(
+ expr);
+ }
+ return contexts;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected static <O> Context<O>[] newInstance(int size) {
+ // fixme how to instanciate a typed array with no checking warning ?
+ return new Context[size];
+ }
+}
Property changes on: trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/DecoratorUtils.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/JXPathDecorator.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/JXPathDecorator.java (rev 0)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/JXPathDecorator.java 2011-07-31 13:25:21 UTC (rev 2155)
@@ -0,0 +1,263 @@
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Utils
+ *
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2004 - 2011 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+package org.nuiton.util.decorator;
+
+import org.apache.commons.jxpath.JXPathContext;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * JXPath decorator based on {@link String#format(String, Object...)} method.
+ * <p/>
+ * To use it, give to him a expression where all jxpath to apply on bean are
+ * boxed in <code>${}</code>.
+ * <p/>
+ * After the jxpath token you must specifiy the formatter to apply of the
+ * jxpath token.
+ * <p/>
+ * For example :
+ * <pre>
+ * Decorator<Object> d = DecoratorUtils.newJXPathDecorator(
+ * JXPathDecorator.class,"expr = ${expressions}$s");
+ * assert "expr = %1$s" == d.getExpression();
+ * assert 1 == d.getNbToken();
+ * assert java.util.Arrays.asList("expression") == d.getTokens();
+ * assert "expr = %1$s" == d.toString(d);
+ * </pre>
+ *
+ * @param <O> type of data to decorate
+ * @author tchemit <chemit(a)codelutin.com>
+ * @see Decorator
+ * @since 2.2.1
+ */
+public class JXPathDecorator<O> extends Decorator<O> {
+
+ private static final long serialVersionUID = 1L;
+
+ /** Logger */
+ private static final Log log = LogFactory.getLog(JXPathDecorator.class);
+
+ /** the computed context of the decorator */
+ protected Context<O> context;
+
+ /** nb jxpath tokens to compute */
+ protected int nbToken;
+
+ /** the initial expression used to compute the decorator context. */
+ protected String initialExpression;
+
+ protected JXPathDecorator(Class<O> internalClass,
+ String expression,
+ Context<O> context)
+ throws IllegalArgumentException, NullPointerException {
+ super(internalClass);
+ initialExpression = expression;
+ if (context != null) {
+ setContext(context);
+ }
+ }
+
+ @Override
+ public String toString(Object bean) {
+ if (bean == null) {
+ return null;
+ }
+ JXPathContext jxcontext = JXPathContext.newContext(bean);
+ Object[] args = new Object[nbToken];
+
+ for (int i = 0; i < nbToken; i++) {
+ try {
+ args[i] = getTokenValue(jxcontext, context.tokens[i]);
+ } catch (Exception e) {
+ if (log.isErrorEnabled()) {
+ log.error("can not obtain token " + context.tokens[i]
+ + " on object of type " +
+ bean.getClass().getName() +
+ " for reason " + e.getMessage(), e);
+ }
+
+ }
+ }
+
+ String result;
+ try {
+ result = String.format(context.expression, args);
+ } catch (Exception eee) {
+ if (log.isErrorEnabled()) {
+ log.error("Could not format " + context.expression + "" +
+ " with args : " + Arrays.toString(args), eee);
+ }
+ result = "";
+ }
+ return result;
+ }
+
+ public String getProperty(int pos) {
+ return getTokens()[pos];
+ }
+
+ public String getExpression() {
+ return context.expression;
+ }
+
+ public String[] getTokens() {
+ return context.tokens;
+ }
+
+ public int getNbToken() {
+ return nbToken;
+ }
+
+ public String getInitialExpression() {
+ return initialExpression;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + '<' + context + '>';
+ }
+
+ public void setContext(Context<O> context) {
+ this.context = context;
+ nbToken = context.tokens.length;
+ // always reset comparator
+ //this.context.comparator = null;
+ if (log.isDebugEnabled()) {
+ log.debug(context);
+ }
+ }
+
+ @SuppressWarnings({"unchecked"})
+ protected Comparator<O> getComparator(int pos) {
+ ensureTokenIndex(this, pos);
+ return context.getComparator(pos);
+ }
+
+ @SuppressWarnings({"unchecked"})
+ protected Comparable<Comparable<?>> getTokenValue(JXPathContext jxcontext,
+ String token) {
+ // assume all values are comparable
+ return (Comparable<Comparable<?>>) jxcontext.getValue(token);
+ }
+
+ public static class JXPathComparator<O> implements Comparator<O> {
+
+ protected Map<O, Comparable<Comparable<?>>> valueCache;
+
+ private final String expression;
+
+ public JXPathComparator(String expression) {
+ this.expression = expression;
+ valueCache = new HashMap<O, Comparable<Comparable<?>>>();
+ }
+
+ @Override
+ public int compare(O o1, O o2) {
+ Comparable<Comparable<?>> c1 = valueCache.get(o1);
+ Comparable<Comparable<?>> c2 = valueCache.get(o2);
+ if (c1 == null) {
+ if (c2 == null) {
+ return 0;
+ }
+ return 1;
+ }
+ if (c2 == null) {
+ return -1;
+ }
+ return c1.compareTo(c2);
+ }
+
+ public void clear() {
+ valueCache.clear();
+ }
+
+ public void init(JXPathDecorator<O> decorator, List<O> datas) {
+ clear();
+ for (O data : datas) {
+ JXPathContext jxcontext = JXPathContext.newContext(data);
+ Comparable<Comparable<?>> key;
+ key = decorator.getTokenValue(jxcontext, expression);
+ valueCache.put(data, key);
+ }
+ }
+ }
+
+ public static class Context<O> implements Serializable {
+
+ /**
+ * expression to format using {@link String#format(String, Object...)},
+ * all variables are compute using using the jxpath tokens.
+ */
+ protected String expression;
+
+ /** list of jxpath tokens to apply on expression */
+ protected String[] tokens;
+
+ protected transient Comparator<O> comparator;
+
+ private static final long serialVersionUID = 1L;
+
+ public Context(String expression, String[] tokens) {
+ this.expression = expression;
+ this.tokens = tokens;
+ }
+
+ public String getFirstProperty() {
+ return tokens[0];
+ }
+
+ public Comparator<O> getComparator(int pos) {
+ if (comparator == null) {
+ comparator = new JXPathComparator<O>(tokens[pos]);
+ }
+ return comparator;
+ }
+
+ public void setComparator(Comparator<O> comparator) {
+ this.comparator = comparator;
+ }
+
+ @Override
+ public String toString() {
+ return "<expression:" + expression + ", tokens:" +
+ Arrays.toString(tokens) + '>';
+ }
+ }
+
+ protected static void ensureTokenIndex(JXPathDecorator<?> decorator, int pos) {
+ if (pos < -1 || pos > decorator.getNbToken()) {
+ throw new ArrayIndexOutOfBoundsException(
+ "token index " + pos + " is out of bound, can be inside [" +
+ 0 + ',' + decorator.nbToken + ']');
+ }
+ }
+}
Property changes on: trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/JXPathDecorator.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/MapPropertyHandler.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/MapPropertyHandler.java (rev 0)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/MapPropertyHandler.java 2011-07-31 13:25:21 UTC (rev 2155)
@@ -0,0 +1,180 @@
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Utils
+ *
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2004 - 2011 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+package org.nuiton.util.decorator;
+
+import org.apache.commons.jxpath.DynamicPropertyHandler;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A extended handler to deal with map in JXPath contexts.
+ * <p/>
+ * The basic one in JXPath api only deals with map keys as string.
+ * <p/>
+ * We offers a hook in method {@link #getKey(Object)} to obtain a string
+ * representation of a real object in map (key or value).
+ * <p/>
+ * More over, you can also access directly to a key or a value, using this
+ * syntax :
+ * <p/>
+ * <pre>context.getValue(".[@name='key:programme2']")</pre>
+ * <pre>context.getValue(".[@name='value:programme2']")</pre>
+ * <p/>
+ * If the values are iterable, then will scan inot it when looking for a direct
+ * value.
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @see DynamicPropertyHandler
+ * @since 2.2.1
+ */
+public class MapPropertyHandler implements DynamicPropertyHandler {
+
+ /** Logger */
+ private static final Log log =
+ LogFactory.getLog(MapPropertyHandler.class);
+
+ @Override
+ public String[] getPropertyNames(Object object) {
+ Map<?, ?> map = (Map<?, ?>) object;
+ Set<?> set = map.keySet();
+ String[] names = new String[set.size()];
+ Iterator<?> it = set.iterator();
+ for (int i = 0; i < names.length; i++) {
+ Object o = it.next();
+ names[i] = getKey(o);
+ }
+ return names;
+ }
+
+ @Override
+ public Object getProperty(Object object, String propertyName) {
+ Map<?, ?> map = (Map<?, ?>) object;
+ boolean getKey = false;
+ Object property0;
+ if (propertyName.startsWith("value:")) {
+ propertyName = propertyName.substring(6);
+ if (log.isDebugEnabled()) {
+ log.debug("property value name " + propertyName);
+ }
+ property0 = getPropertyValue(map, propertyName);
+ if (log.isDebugEnabled()) {
+ log.debug("property value = " + property0);
+ }
+ return property0;
+ }
+ if (propertyName.startsWith("key:")) {
+ propertyName = propertyName.substring(4);
+ getKey = true;
+ }
+ property0 = getPropertyKey(map, propertyName);
+ Object result = null;
+ if (property0 != null) {
+ if (getKey) {
+ result = property0;
+ } else {
+ result = map.get(property0);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public void setProperty(Object object, String propertyName, Object value) {
+ Map map = (Map) object;
+ Object property0 = getPropertyKey(map, propertyName);
+ if (property0 != null) {
+ map.put(property0, value);
+ }
+ }
+
+ /**
+ * Obtain the key from the map keys which matches the given {@code key}.
+ * <p/>
+ * To compare object ot string, please refers to the method {@link
+ * #getKey(Object)}.
+ *
+ * @param map the map to scan
+ * @param key the string representation of the required key as object
+ * @return the found key, or {@code null} if not found.
+ */
+ public Object getPropertyKey(Map<?, ?> map, String key) {
+ Set<?> set = map.keySet();
+ for (Object o : set) {
+ String k = getKey(o);
+ if (key.equals(k)) {
+ return o;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Obtain the value from the map values which matches the given {@code
+ * value}.
+ * <p/>
+ * To compare object to string, please refer to the method {@link
+ * #getKey(Object)}.
+ *
+ * @param map the map to scan
+ * @param value the string representation of the value
+ * @return the found value, or {@code null} if not found.}
+ */
+ public Object getPropertyValue(Map<?, ?> map, String value) {
+ Collection<?> set = map.values();
+ for (Object o : set) {
+ if (o instanceof Iterable<?>) {
+ Iterable<?> c = (Iterable<?>) o;
+ for (Object oo : c) {
+ String k = getKey(oo);
+ if (value.equals(k)) {
+ return oo;
+ }
+ }
+ continue;
+ }
+ String k = getKey(o);
+ if (value.equals(k)) {
+ return o;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Obtain a string representation of an object.
+ *
+ * @param o the object to decorate
+ * @return the string representation of the object
+ */
+ protected String getKey(Object o) {
+ String k = String.valueOf(o);
+ return k;
+ }
+}
Property changes on: trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/MapPropertyHandler.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/MultiJXPathDecorator.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/MultiJXPathDecorator.java (rev 0)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/MultiJXPathDecorator.java 2011-07-31 13:25:21 UTC (rev 2155)
@@ -0,0 +1,125 @@
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Utils
+ *
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2004 - 2011 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+package org.nuiton.util.decorator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.util.Comparator;
+
+/**
+ * {@link JXPathDecorator} implementation with multiple contexts.
+ *
+ * @param <O> type of data to decorate
+ * @author tchemit <chemit(a)codelutin.com>
+ * @see Decorator
+ * @since 2.2.1
+ */
+public class MultiJXPathDecorator<O> extends JXPathDecorator<O> {
+
+ private static final long serialVersionUID = 1L;
+
+ /** Logger */
+ private static final Log log =
+ LogFactory.getLog(MultiJXPathDecorator.class);
+
+ /** Contexts of the decorator */
+ protected Context<O>[] contexts;
+
+ /** context separator */
+ protected String separator;
+
+ /** context separator replacement */
+ protected String separatorReplacement;
+
+ protected MultiJXPathDecorator(
+ Class<O> internalClass,
+ String expression,
+ String separator,
+ String separatorReplacement,
+ Context<O>[] contexts) throws IllegalArgumentException,
+ NullPointerException {
+ super(internalClass, expression, null);
+ this.separator = separator;
+ this.separatorReplacement = separatorReplacement;
+ this.contexts = contexts;
+
+ setContextIndex(0);
+
+ if (log.isDebugEnabled()) {
+ log.debug(expression + " --> " + context);
+ }
+ }
+
+ protected MultiJXPathDecorator(
+ Class<O> internalClass,
+ String expression,
+ String separator,
+ String separatorReplacement) throws IllegalArgumentException,
+ NullPointerException {
+ this(internalClass,
+ expression,
+ separator,
+ separatorReplacement,
+ DecoratorUtils.<O>createMultiJXPathContext(expression,
+ separator,
+ separatorReplacement)
+ );
+ }
+
+ public void setContextIndex(int index) {
+ ensureContextIndex(this, index);
+ setContext(contexts[index]);
+ }
+
+ public int getNbContext() {
+ return contexts.length;
+ }
+
+ public String getSeparator() {
+ return separator;
+ }
+
+ public String getSeparatorReplacement() {
+ return separatorReplacement;
+ }
+
+ @Override
+ protected Comparator<O> getComparator(int pos) {
+ ensureContextIndex(this, pos);
+ Context<O> context1 = contexts[pos];
+ return context1.getComparator(0);
+ }
+
+ protected void ensureContextIndex(MultiJXPathDecorator<?> decorator,
+ int pos) {
+ if (pos < -1 || pos > decorator.contexts.length) {
+ throw new ArrayIndexOutOfBoundsException(
+ "context index " + pos +
+ " is out of bound, can be inside [" + 0 + "," +
+ decorator.contexts.length + "]");
+ }
+ }
+}
Property changes on: trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/MultiJXPathDecorator.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/PropertyDecorator.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/PropertyDecorator.java (rev 0)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/PropertyDecorator.java 2011-07-31 13:25:21 UTC (rev 2155)
@@ -0,0 +1,101 @@
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Utils
+ *
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2004 - 2011 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+package org.nuiton.util.decorator;
+
+import org.apache.commons.beanutils.PropertyUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+
+/**
+ * Simple property decorator based on {@link String#format(String, Object...)}
+ * method.
+ * <p/>
+ * To use it, give him a class and the property name to render.
+ * <p/>
+ * For example :
+ * <pre>
+ * Decorator<Object> d = DecoratorUtils.newPropertyDecorator(PropertyDecorator.class,"property");
+ * </pre>
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @param <O> type of data to decorate
+ * @see Decorator
+ * @since 2.2.1
+ */
+public class PropertyDecorator<O> extends Decorator<O> {
+
+ private static final long serialVersionUID = 1L;
+
+ /** Logger */
+ static private final Log log = LogFactory.getLog(PropertyDecorator.class);
+
+ /** name of property */
+ protected String property;
+
+ protected transient Method m;
+
+ @Override
+ public String toString(Object bean) {
+ try {
+ return getM().invoke(bean) + "";
+ } catch (Exception e) {
+ log.error("could not convert for reason : " + e, e);
+ return "";
+ }
+ }
+
+ public String getProperty() {
+ return property;
+ }
+
+ protected PropertyDecorator(Class<O> internalClass,
+ String property) throws NullPointerException {
+ super(internalClass);
+ if (property == null) {
+ throw new NullPointerException("property can not be null.");
+ }
+ this.property = property;
+ // init method
+ getM();
+ }
+
+ protected Method getM() {
+ if (m == null) {
+ for (PropertyDescriptor propertyDescriptor : PropertyUtils.getPropertyDescriptors(internalClass)) {
+ if (propertyDescriptor.getName().equals(property)) {
+ m = propertyDescriptor.getReadMethod();
+ break;
+ }
+ }
+ if (m == null) {
+ throw new IllegalArgumentException("could not find the property " + property + " in " + internalClass);
+ }
+ }
+ return m;
+ }
+}
Property changes on: trunk/nuiton-utils/src/main/java/org/nuiton/util/decorator/PropertyDecorator.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Modified: trunk/nuiton-utils/src/test/java/org/nuiton/util/MatrixMapTest.java
===================================================================
--- trunk/nuiton-utils/src/test/java/org/nuiton/util/MatrixMapTest.java 2011-07-19 16:46:06 UTC (rev 2154)
+++ trunk/nuiton-utils/src/test/java/org/nuiton/util/MatrixMapTest.java 2011-07-31 13:25:21 UTC (rev 2155)
@@ -1,4 +1,28 @@
/*
+ * #%L
+ * Nuiton Utils :: Nuiton Utils
+ *
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2004 - 2011 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+/*
* Copyright (c) 2011 poussin. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
Property changes on: trunk/nuiton-utils/src/test/java/org/nuiton/util/MatrixMapTest.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/Data.java
===================================================================
--- trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/Data.java (rev 0)
+++ trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/Data.java 2011-07-31 13:25:21 UTC (rev 2155)
@@ -0,0 +1,61 @@
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Utils
+ *
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2004 - 2011 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+package org.nuiton.util.decorator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Data {
+
+ int pos;
+
+ String name;
+
+ protected static List<Data> generate(int nb) {
+ List<Data> datas = new ArrayList<Data>(nb);
+ for (int i = 0; i < nb; i++) {
+ datas.add(new Data(i, "name_" + (nb - i)));
+ }
+ return datas;
+ }
+
+ Data(int pos, String name) {
+ this.pos = pos;
+ this.name = name;
+ }
+
+ public int getPos() {
+ return pos;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return "Data{pos=" + pos + ", name=\'" + name + '\'' + '}';
+ }
+}
Property changes on: trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/Data.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/DecoratorProviderTest.java
===================================================================
--- trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/DecoratorProviderTest.java (rev 0)
+++ trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/DecoratorProviderTest.java 2011-07-31 13:25:21 UTC (rev 2155)
@@ -0,0 +1,176 @@
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Utils
+ *
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2004 - 2011 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+package org.nuiton.util.decorator;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.File;
+
+/**
+ * User: chemit
+ * Date: 28 oct. 2009
+ * Time: 21:28:46
+ */
+public class DecoratorProviderTest {
+ private static final String BY_NAME = "name";
+
+ static class MyDecoratorProvider extends DecoratorProvider {
+
+ @Override
+ protected void loadDecorators() {
+
+ registerPropertyDecorator(File.class, "name");
+ registerPropertyDecorator(File.class, BY_NAME, "parent");
+
+ registerJXPathDecorator(Class.class, "${simpleName}$s");
+ registerJXPathDecorator(Class.class, BY_NAME, "${name}$s");
+
+ registerMultiJXPathDecorator(Data.class, "${name}$s", "-", " ");
+ registerMultiJXPathDecorator(Data.class, BY_NAME, "${pos}$d", "-", " ");
+ }
+ }
+
+ static DecoratorProvider provider;
+
+ @BeforeClass
+ public static void beforeTest() throws Exception {
+ provider = new MyDecoratorProvider();
+ }
+
+ @Test
+ public void testGetDecoratorByObject() throws Exception {
+
+ File f = new File("myFile");
+ Data d = new Data(0, "name");
+ Class<?> k = File.class;
+
+ Decorator<File> fileDecorator = provider.getDecorator(f);
+ Assert.assertNotNull(fileDecorator);
+ Assert.assertEquals(File.class, fileDecorator.getInternalClass());
+ Assert.assertEquals("myFile", fileDecorator.toString(f));
+
+ Decorator<?> classDecorator = provider.getDecorator(Class.class);
+ Assert.assertNotNull(classDecorator);
+ Assert.assertEquals(Class.class, classDecorator.getInternalClass());
+ Assert.assertEquals("File", classDecorator.toString(k));
+
+ Decorator<Data> dataDecorator = provider.getDecorator(d);
+ Assert.assertNotNull(dataDecorator);
+ Assert.assertEquals(Data.class, dataDecorator.getInternalClass());
+ Assert.assertEquals("name", dataDecorator.toString(d));
+ }
+
+ @Test
+ public void testGetDecoratorByObjectAndName() throws Exception {
+
+ File f = new File("myFile");
+ Data d = new Data(0, "name");
+ Class<?> k = File.class;
+
+ Decorator<File> fileDecorator = provider.getDecorator(f, BY_NAME);
+ Assert.assertNotNull(fileDecorator);
+ Assert.assertEquals(File.class, fileDecorator.getInternalClass());
+ Assert.assertEquals("null", fileDecorator.toString(f));
+
+ Decorator<Class> classDecorator = provider.getDecorator(Class.class, BY_NAME);
+ Assert.assertNotNull(classDecorator);
+ Assert.assertEquals(Class.class, classDecorator.getInternalClass());
+ Assert.assertEquals("java.io.File", classDecorator.toString(k));
+
+
+ Decorator<Data> dataDecorator = provider.getDecorator(d, BY_NAME);
+ Assert.assertNotNull(dataDecorator);
+ Assert.assertEquals(Data.class, dataDecorator.getInternalClass());
+ Assert.assertEquals("0", dataDecorator.toString(d));
+ }
+
+ @Test
+ public void testGetDecoratorByType() throws Exception {
+
+ File f = new File("myFile");
+ Data d = new Data(0, "name");
+ Class<?> k = File.class;
+
+ Decorator<File> fileDecorator = provider.getDecorator(File.class);
+ Assert.assertNotNull(fileDecorator);
+ Assert.assertEquals(File.class, fileDecorator.getInternalClass());
+ Assert.assertEquals("myFile", fileDecorator.toString(f));
+
+ Decorator<Class> classDecorator = provider.getDecorator(Class.class);
+ Assert.assertNotNull(classDecorator);
+ Assert.assertEquals(Class.class, classDecorator.getInternalClass());
+ Assert.assertEquals("File", classDecorator.toString(k));
+
+ Decorator<Data> dataDecorator = provider.getDecorator(Data.class);
+ Assert.assertNotNull(dataDecorator);
+ Assert.assertEquals(Data.class, dataDecorator.getInternalClass());
+ Assert.assertEquals("name", dataDecorator.toString(d));
+ }
+
+ @Test
+ public void testGetDecoratorByTypeAndName() throws Exception {
+ File f = new File("myFile");
+ Data d = new Data(0, "name");
+ Class<?> k = File.class;
+
+ Decorator<File> fileDecorator = provider.getDecorator(File.class, BY_NAME);
+ Assert.assertNotNull(fileDecorator);
+ Assert.assertEquals(File.class, fileDecorator.getInternalClass());
+ Assert.assertEquals("null", fileDecorator.toString(f));
+
+ Decorator<Class> classDecorator = provider.getDecorator(Class.class, BY_NAME);
+ Assert.assertNotNull(classDecorator);
+ Assert.assertEquals(Class.class, classDecorator.getInternalClass());
+ Assert.assertEquals("java.io.File", classDecorator.toString(k));
+
+
+ Decorator<Data> dataDecorator = provider.getDecorator(Data.class, BY_NAME);
+ Assert.assertNotNull(dataDecorator);
+ Assert.assertEquals(Data.class, dataDecorator.getInternalClass());
+ Assert.assertEquals("0", dataDecorator.toString(d));
+ }
+
+
+ @Test
+ public void testReload() throws Exception {
+
+ int nb = provider.getDecorators().size();
+ Assert.assertTrue(nb > 0);
+
+ provider.reload();
+
+ Assert.assertEquals(nb, provider.getDecorators().size());
+ }
+
+ @Test
+ public void testClear() throws Exception {
+ provider.clear();
+
+ Assert.assertTrue(provider.getDecorators().isEmpty());
+ }
+
+}
Property changes on: trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/DecoratorProviderTest.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/JXPathContextTester.java
===================================================================
--- trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/JXPathContextTester.java (rev 0)
+++ trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/JXPathContextTester.java 2011-07-31 13:25:21 UTC (rev 2155)
@@ -0,0 +1,57 @@
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Utils
+ *
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2004 - 2011 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+package org.nuiton.util.decorator;
+
+import org.apache.commons.jxpath.JXPathContext;
+import org.junit.After;
+import org.junit.Assert;
+
+/**
+ * A simple class to test JXPath context.
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0.1
+ */
+public abstract class JXPathContextTester {
+
+ JXPathContext context;
+
+ @After
+ public void after() {
+ context = null;
+
+ }
+
+ protected void newContext(Object o) {
+ context = JXPathContext.newContext(o);
+ }
+
+ protected <T> T getValue(String path) {
+ Assert.assertNotNull("pas de context initialisé", context);
+ Object value = context.getValue(path);
+ return (T) value;
+ }
+
+}
Property changes on: trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/JXPathContextTester.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/JXPathDecoratorTest.java
===================================================================
--- trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/JXPathDecoratorTest.java (rev 0)
+++ trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/JXPathDecoratorTest.java 2011-07-31 13:25:21 UTC (rev 2155)
@@ -0,0 +1,173 @@
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Utils
+ *
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2004 - 2011 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+package org.nuiton.util.decorator;
+
+import org.junit.After;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 1.7.2 (was previously {@code jaxx.runtime.JXPathDecoratorTest}).
+ */
+public class JXPathDecoratorTest {
+
+
+ protected JXPathDecorator<?> decorator;
+
+ protected String expected;
+
+ protected String result;
+
+ @After
+ public void after() {
+ decorator = null;
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testNullInternalClass() throws Exception {
+ decorator = DecoratorUtils.newJXPathDecorator(null, "hello");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testMissingRightBrace() throws Exception {
+ decorator = DecoratorUtils.newJXPathDecorator(Object.class, "${haha");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testMissingRightBrace2() throws Exception {
+ decorator = DecoratorUtils.newJXPathDecorator(Object.class, "${haha${hum}");
+ }
+
+ @Test
+ public void testNullBean() throws Exception {
+ decorator = DecoratorUtils.newJXPathDecorator(Object.class, "hello");
+ expected = "hello";
+ assertEquals(expected, decorator.getExpression());
+ assertEquals(0, decorator.nbToken);
+ assertEquals(0, decorator.getTokens().length);
+
+ result = decorator.toString(null);
+ assertEquals(null, result);
+ }
+
+ @Test
+ public void testNoJXPath() throws Exception {
+ decorator = DecoratorUtils.newJXPathDecorator(Object.class, "hello");
+ expected = "hello";
+ assertEquals(expected, decorator.getExpression());
+ assertEquals(0, decorator.nbToken);
+ assertEquals(0, decorator.getTokens().length);
+
+ result = decorator.toString(this);
+ assertEquals(expected, result);
+ }
+
+ @Test
+ public void testDecorator() throws Exception {
+
+ decorator = DecoratorUtils.newJXPathDecorator(JXPathDecorator.class, "${expression}$s - ${nbToken}$d");
+ assertEquals("%1$s - %2$d", decorator.getExpression());
+ assertDecoratorInternal();
+
+ decorator = DecoratorUtils.newJXPathDecorator(JXPathDecorator.class, "${expression}${nbToken}");
+ assertEquals("%1%2", decorator.getExpression());
+ assertDecoratorInternal();
+
+ decorator = DecoratorUtils.newJXPathDecorator(JXPathDecorator.class, "before ${expression}$s - ${nbToken}$d after");
+ assertEquals("before %1$s - %2$d after", decorator.getExpression());
+ assertDecoratorInternal();
+
+ decorator = DecoratorUtils.newJXPathDecorator(JXPathDecorator.class, "before${expression}$s-${nbToken}$dafter");
+ assertEquals("before%1$s-%2$dafter", decorator.getExpression());
+ assertDecoratorInternal();
+ }
+
+ @Test
+ public void testDecoratorEspcapeCharacters() throws Exception {
+
+ decorator = DecoratorUtils.newJXPathDecorator(JXPathDecorator.class, "(${expression}$s) - ${nbToken}$d");
+ assertEquals("(%1$s) - %2$d", decorator.getExpression());
+ String s = decorator.toString(decorator);
+ System.out.println("s=" + s);
+ assertDecoratorInternal();
+
+ }
+
+ @Test
+ public void testSort() throws Exception {
+
+ List<Data> datas = Data.generate(10);
+
+ JXPathDecorator<Data> d = DecoratorUtils.newJXPathDecorator(Data.class, "${pos}$d ${name}$s");
+
+ List<Data> sortData = new ArrayList<Data>(datas);
+ DecoratorUtils.sort(d, sortData, 0);
+ for (int i = 0; i < datas.size(); i++) {
+ Data data = datas.get(i);
+ Data sData = sortData.get(i);
+ assertEquals(data, sData);
+ }
+ Collections.sort(datas, new Comparator<Data>() {
+ @Override
+ public int compare(Data o1, Data o2) {
+ return o1.name.compareTo(o2.name);
+ }
+ });
+ JXPathDecorator.Context<Data> context = d.context;
+ context.setComparator(null);
+ DecoratorUtils.sort(d, sortData, 1);
+ for (int i = 0; i < datas.size(); i++) {
+ Data data = datas.get(i);
+ Data sData = sortData.get(i);
+ assertEquals(data, sData);
+ }
+ }
+
+
+ public void assertDecoratorInternal(String... tokens) {
+ assertTokens(tokens);
+ expected = String.format(decorator.getExpression(), decorator.getExpression(), decorator.getNbToken());
+ result = decorator.toString(decorator);
+ assertEquals(expected, result);
+ }
+
+ private void assertTokens(String... tokens) {
+ if (tokens.length == 0) {
+ tokens = new String[]{"expression", "nbToken"};
+ }
+ assertEquals(2, decorator.nbToken);
+ assertEquals(2, decorator.getTokens().length);
+ assertEquals(tokens[0], decorator.getTokens()[0]);
+ assertEquals(tokens[1], decorator.getTokens()[1]);
+ }
+
+}
Property changes on: trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/JXPathDecoratorTest.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/MapPropertyHandlerTest.java
===================================================================
--- trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/MapPropertyHandlerTest.java (rev 0)
+++ trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/MapPropertyHandlerTest.java 2011-07-31 13:25:21 UTC (rev 2155)
@@ -0,0 +1,128 @@
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Utils
+ *
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2004 - 2011 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+package org.nuiton.util.decorator;
+
+import org.apache.commons.jxpath.JXPathIntrospector;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Tests the class {@link MapPropertyHandler}.
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.0.1
+ */
+public class MapPropertyHandlerTest extends JXPathContextTester {
+
+
+ /** Logger */
+ private static final Log log =
+ LogFactory.getLog(MapPropertyHandlerTest.class);
+
+ private static final String TWO_ID = "two";
+
+ private static final String ONE_ID = "one";
+
+ @BeforeClass
+ public static void beforeClass() {
+
+ // pour initialiser le JXPathContext
+ JXPathIntrospector.registerDynamicClass(
+ Map.class,
+ MapPropertyHandler.class
+ );
+ }
+
+ @Before
+ public void setUp() {
+
+ Map<String, Boolean> map = new TreeMap<String, Boolean>();
+ map.put(ONE_ID, true);
+ map.put(TWO_ID, false);
+
+ if (log.isInfoEnabled()) {
+ log.info("init map : " + map);
+ }
+ newContext(map);
+ }
+
+ @Test
+ public void testValues() throws Exception {
+
+ Boolean value;
+
+ value = (Boolean) getValue(".[@name='one']");
+ Assert.assertNotNull(value);
+ Assert.assertTrue(value);
+
+ value = (Boolean) getValue(".[@name='two']");
+ Assert.assertNotNull(value);
+ Assert.assertFalse(value);
+
+ value = (Boolean) getValue(".[@name='three']");
+ Assert.assertNull(value);
+ }
+
+ @Test
+ public void testKey() throws Exception {
+
+ String key;
+
+ key = (String) getValue(".[@name='key:one']");
+ Assert.assertNotNull(key);
+ Assert.assertEquals(ONE_ID, key);
+
+ key = (String) getValue(".[@name='key:two']");
+ Assert.assertNotNull(key);
+ Assert.assertEquals(TWO_ID, key);
+
+ key = (String) getValue(".[@name='key:fake']");
+ Assert.assertNull(key);
+ }
+
+ @Test
+ public void testValue() throws Exception {
+
+ Boolean value;
+
+ value = (Boolean) getValue(".[@name='value:true']");
+ Assert.assertNotNull(value);
+ Assert.assertTrue(value);
+
+ value = (Boolean) getValue(".[@name='value:false']");
+ Assert.assertNotNull(value);
+ Assert.assertFalse(value);
+
+ value = (Boolean) getValue(".[@name='value:fake']");
+ Assert.assertNull(value);
+ }
+}
Property changes on: trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/MapPropertyHandlerTest.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/MultiJXPathDecoratorTest.java
===================================================================
--- trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/MultiJXPathDecoratorTest.java (rev 0)
+++ trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/MultiJXPathDecoratorTest.java 2011-07-31 13:25:21 UTC (rev 2155)
@@ -0,0 +1,254 @@
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Utils
+ *
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2004 - 2011 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+package org.nuiton.util.decorator;
+
+import org.junit.After;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 1.7.2 (was previously {@code jaxx.runtime.MultiJXPathDecoratorTest}).
+ */
+public class MultiJXPathDecoratorTest {
+
+ protected MultiJXPathDecorator<?> decorator;
+
+ protected String expected;
+
+ protected String result;
+
+ @After
+ public void after() {
+ decorator = null;
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testNullInternalClass() throws Exception {
+ decorator = DecoratorUtils.newMultiJXPathDecorator(null, "hello", "#");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testMissingRightBrace() throws Exception {
+ decorator = DecoratorUtils.newMultiJXPathDecorator(Object.class, "${haha", "#");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testMissingRightBrace2() throws Exception {
+ decorator = DecoratorUtils.newMultiJXPathDecorator(Object.class, "${haha${hum}", "#");
+ }
+
+ @Test
+ public void testNullBean() throws Exception {
+ decorator = DecoratorUtils.newMultiJXPathDecorator(Object.class, "hello", "");
+ expected = "hello";
+ assertEquals(expected, decorator.getExpression());
+ assertEquals(0, decorator.nbToken);
+ assertEquals(0, decorator.getTokens().length);
+
+ result = decorator.toString(null);
+ assertEquals(null, result);
+ }
+
+ @Test
+ public void testMultiDecorator() throws Exception {
+
+ decorator = DecoratorUtils.newMultiJXPathDecorator(JXPathDecorator.class, "${expression}$s#${nbToken}$d", "#", " - ");
+ assertEquals("%1$s - %2$d", decorator.getExpression());
+ assertDecoratorInternal();
+ assertEquals(2, decorator.contexts.length);
+ decorator.setContextIndex(1);
+ assertEquals("%1$d - %2$s", decorator.getExpression());
+ assertTokens("nbToken", "expression");
+ expected = String.format(decorator.getExpression(), decorator.getNbToken(), decorator.getExpression());
+ result = decorator.toString(decorator);
+ assertEquals(expected, result);
+
+ decorator = DecoratorUtils.newMultiJXPathDecorator(JXPathDecorator.class, "${expression}$s ## ${nbToken}$d", " ## ", " - ");
+ assertEquals("%1$s - %2$d", decorator.getExpression());
+ assertDecoratorInternal();
+ assertEquals(2, decorator.contexts.length);
+ decorator.setContextIndex(1);
+ assertEquals("%1$d - %2$s", decorator.getExpression());
+ assertTokens("nbToken", "expression");
+ expected = String.format(decorator.getExpression(), decorator.getNbToken(), decorator.getExpression());
+ result = decorator.toString(decorator);
+ assertEquals(expected, result);
+ }
+
+ @Test
+ public void testMultiDecorator2() throws Exception {
+
+ decorator = DecoratorUtils.newMultiJXPathDecorator(JXPathDecorator.class, "${expression}$s#${nbToken}$d#${separator}$s", "#", " - ");
+
+ assertEquals("%1$s - %2$d - %3$s", decorator.getExpression());
+ assertTokens("expression", "nbToken", "separator");
+ assertEquals(3, decorator.contexts.length);
+
+ expected = String.format(decorator.getExpression(), decorator.getExpression(), decorator.getNbToken(), decorator.getSeparator());
+ result = decorator.toString(decorator);
+ assertEquals(expected, result);
+
+ decorator.setContextIndex(1);
+ assertEquals("%1$d - %2$s - %3$s", decorator.getExpression());
+ assertTokens("nbToken", "separator", "expression");
+ expected = String.format(decorator.getExpression(), decorator.getNbToken(), decorator.getSeparator(), decorator.getExpression());
+ result = decorator.toString(decorator);
+ assertEquals(expected, result);
+
+ decorator.setContextIndex(2);
+ assertEquals("%1$s - %2$s - %3$d", decorator.getExpression());
+ assertTokens("separator", "expression", "nbToken");
+
+ expected = String.format(decorator.getExpression(), decorator.getSeparator(), decorator.getExpression(), decorator.getNbToken());
+ result = decorator.toString(decorator);
+ assertEquals(expected, result);
+ }
+
+
+ @Test
+ public void testDecoratorEspcapeCharacters() throws Exception {
+
+ decorator = DecoratorUtils.newMultiJXPathDecorator(JXPathDecorator.class, "(${expression}$s)#${nbToken}$d", "#", " - ");
+ assertEquals("(%1$s) - %2$d", decorator.getExpression());
+ assertTokens("expression", "nbToken");
+ assertEquals(2, decorator.contexts.length);
+ expected = String.format(decorator.getExpression(), decorator.getExpression(), decorator.getNbToken());
+ result = decorator.toString(decorator);
+ System.out.println("s=" + result);
+ assertEquals(expected, result);
+
+ decorator = DecoratorUtils.newMultiJXPathDecorator(JXPathDecorator.class, "${nbToken}$d#(${expression}$s)", "#", " - ");
+ assertEquals("%1$d - (%2$s)", decorator.getExpression());
+ assertTokens("nbToken", "expression");
+ assertEquals(2, decorator.contexts.length);
+ expected = String.format(decorator.getExpression(), decorator.getNbToken(), decorator.getExpression());
+ result = decorator.toString(decorator);
+ System.out.println("s=" + result);
+ assertEquals(expected, result);
+
+ DecoratorProvider provider = new DecoratorProvider() {
+
+ @Override
+ protected void loadDecorators() {
+ }
+
+ };
+ provider.registerMultiJXPathDecorator(MultiJXPathDecorator.class, "(${expression}$s)#${nbToken}$d", "#", " - ");
+ decorator = (MultiJXPathDecorator<?>) provider.getDecorator(MultiJXPathDecorator.class);
+
+ assertEquals("(%1$s) - %2$d", decorator.getExpression());
+ assertTokens("expression", "nbToken");
+ assertEquals(2, decorator.contexts.length);
+ expected = String.format(decorator.getExpression(), decorator.getExpression(), decorator.getNbToken());
+ result = decorator.toString(decorator);
+ System.out.println("s=" + result);
+ assertEquals(expected, result);
+
+ }
+
+ @Test
+ public void testMultiDecoratorWithMultiRef() throws Exception {
+
+ decorator = DecoratorUtils.newMultiJXPathDecorator(JXPathDecorator.class, "${expression}$s#${nbToken}$d#${separator}$s %3$s", "#", " - ");
+
+ assertEquals("%1$s - %2$d - %3$s %3$s", decorator.getExpression());
+ assertTokens("expression", "nbToken", "separator");
+ assertEquals(3, decorator.contexts.length);
+
+ expected = String.format(decorator.getExpression(), decorator.getExpression(), decorator.getNbToken(), decorator.getSeparator());
+ result = decorator.toString(decorator);
+ assertEquals(expected, result);
+
+ decorator.setContextIndex(1);
+ assertEquals("%1$d - %2$s %2$s - %3$s", decorator.getExpression());
+ assertTokens("nbToken", "separator", "expression");
+ expected = String.format(decorator.getExpression(), decorator.getNbToken(), decorator.getSeparator(), decorator.getExpression());
+ result = decorator.toString(decorator);
+ assertEquals(expected, result);
+
+ decorator.setContextIndex(2);
+ assertEquals("%1$s %1$s - %2$s - %3$d", decorator.getExpression());
+ assertTokens("separator", "expression", "nbToken");
+
+ expected = String.format(decorator.getExpression(), decorator.getSeparator(), decorator.getExpression(), decorator.getNbToken());
+ result = decorator.toString(decorator);
+ assertEquals(expected, result);
+ }
+
+ @Test
+ public void testSort() throws Exception {
+
+ List<Data> datas = Data.generate(10);
+
+ MultiJXPathDecorator<Data> d = DecoratorUtils.newMultiJXPathDecorator(Data.class, "${pos}$d-${name}$s", "-");
+
+ List<Data> sortData = new ArrayList<Data>(datas);
+ DecoratorUtils.sort(d, sortData, 0);
+ for (int i = 0; i < datas.size(); i++) {
+ Data data = datas.get(i);
+ Data sData = sortData.get(i);
+ assertEquals(data, sData);
+ }
+ Collections.sort(datas, new Comparator<Data>() {
+
+ @Override
+ public int compare(Data o1, Data o2) {
+ return o1.name.compareTo(o2.name);
+ }
+ });
+ d.setContextIndex(1);
+ DecoratorUtils.sort(d, sortData, 1);
+ for (int i = 0; i < datas.size(); i++) {
+ Data data = datas.get(i);
+ Data sData = sortData.get(i);
+ assertEquals(data, sData);
+ }
+ }
+
+ public void assertDecoratorInternal(String... tokens) {
+ assertTokens(tokens);
+ expected = String.format(decorator.getExpression(), decorator.getExpression(), decorator.getNbToken());
+ result = decorator.toString(decorator);
+ assertEquals(expected, result);
+ }
+
+ private void assertTokens(String... tokens) {
+ if (tokens.length == 0) {
+ tokens = new String[]{"expression", "nbToken"};
+ }
+ assertEquals(tokens.length, decorator.nbToken);
+ assertEquals(tokens.length, decorator.getTokens().length);
+ for (int i = 0; i < tokens.length; i++) {
+ assertEquals(tokens[i], decorator.getTokens()[i]);
+ }
+ }
+}
Property changes on: trunk/nuiton-utils/src/test/java/org/nuiton/util/decorator/MultiJXPathDecoratorTest.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Modified: trunk/nuiton-validator/src/license/THIRD-PARTY.properties
===================================================================
--- trunk/nuiton-validator/src/license/THIRD-PARTY.properties 2011-07-19 16:46:06 UTC (rev 2154)
+++ trunk/nuiton-validator/src/license/THIRD-PARTY.properties 2011-07-31 13:25:21 UTC (rev 2155)
@@ -1,15 +1,20 @@
-# Generated by org.nuiton.license.plugin.AddThirdPartyMojo
+# Generated by org.codehaus.mojo.license.AddThirdPartyMojo
#-------------------------------------------------------------------------------
# Already used licenses in project :
# - BSD License
# - Common Public License Version 1.0
# - Lesser General Public License (LGPL) v 3.0
+# - Lesser General Public License (LPGL)
+# - Lesser General Public License (LPGL) v 2.1
+# - Lesser General Public License v2.1,Mozilla Public License 1.1 (MPL)
# - The Apache Software License, Version 2.0
#-------------------------------------------------------------------------------
# Please fill the missing licenses for dependencies :
#
#
-#Wed Jan 26 12:51:06 CET 2011
+#Sun Jul 31 15:22:20 CEST 2011
+asm--asm--3.1--jar=http\://asm.ow2.org/license.html
+asm--asm-commons--3.1--jar=http\://asm.ow2.org/license.html
+asm--asm-tree--3.1--jar=http\://asm.ow2.org/license.html
commons-primitives--commons-primitives--1.0--jar=The Apache Software License, Version 2.0
javassist--javassist--3.8.0.GA--jar=Lesser General Public License v2.1,Mozilla Public License 1.1 (MPL)
-ognl--ognl--3.0--jar=The OpenSymphony Software License 1.1
\ No newline at end of file
1
0
19 Jul '11
Author: bleny
Date: 2011-07-19 18:46:06 +0200 (Tue, 19 Jul 2011)
New Revision: 2154
Url: http://nuiton.org/repositories/revision/nuiton-utils/2154
Log:
removing junk code ; adding a regression test for PeriodDates (issue #1634)
Modified:
trunk/nuiton-utils/src/test/java/org/nuiton/util/PeriodDatesTest.java
Modified: trunk/nuiton-utils/src/test/java/org/nuiton/util/PeriodDatesTest.java
===================================================================
--- trunk/nuiton-utils/src/test/java/org/nuiton/util/PeriodDatesTest.java 2011-07-17 12:11:05 UTC (rev 2153)
+++ trunk/nuiton-utils/src/test/java/org/nuiton/util/PeriodDatesTest.java 2011-07-19 16:46:06 UTC (rev 2154)
@@ -32,6 +32,7 @@
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Ignore;
import org.junit.Test;
import java.text.DateFormat;
@@ -39,6 +40,7 @@
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
+import java.util.concurrent.TimeUnit;
/** @author fdesbois */
public class PeriodDatesTest {
@@ -46,46 +48,9 @@
/** Logger */
private static final Log log = LogFactory.getLog(PeriodDatesTest.class);
-
- @BeforeClass
- public static void setUpClass() throws Exception {
- }
-
- @AfterClass
- public static void tearDownClass() throws Exception {
- }
-
- @Before
- public void setUp() {
- }
-
- @After
- public void tearDown() {
- }
-
- /** Test of createMonthsPeriodFromToday method, of class PeriodDates. */
- //@Test
- public void testCreateMonthsPeriodFromToday() {
- log.info("createMonthsPeriodFromToday");
- }
-
- /** Test of getPattern method, of class PeriodDates. */
- //@Test
- public void testGetPattern() {
- log.info("getPattern");
- }
-
- /** Test of setPattern method, of class PeriodDates. */
- //@Test
- public void testSetPattern() {
- log.info("setPattern");
- }
-
/** Test of initDayOfMonthExtremities method, of class PeriodDates. */
@Test
public void testInitDayOfMonthExtremities() {
- log.info("initDayOfMonthExtremities");
-
PeriodDates period = new PeriodDates();
period.setFromDate(DateUtil.createDate(9,8,7,23,12,2010));
period.setThruDate(DateUtil.createDate(6,5,4,26,12,2010));
@@ -101,41 +66,9 @@
Assert.assertEquals(lastDayOf2010.getTime(), period.getThruDate());
}
- /** Test of setFromDate method, of class PeriodDates. */
- //@Test
- public void testSetFromDate() {
- log.info("setFromDate");
- }
-
- /** Test of getFromDate method, of class PeriodDates. */
- //@Test
- public void testGetFromDate() {
- log.info("getFromDate");
- }
-
- /** Test of getFromMonth method, of class PeriodDates. */
- //@Test
- public void testGetFromMonth() {
- log.info("getFromMonth");
- }
-
- /** Test of setThruDate method, of class PeriodDates. */
- //@Test
- public void testSetThruDate() {
- log.info("setThruDate");
- }
-
- /** Test of getThruDate method, of class PeriodDates. */
- //@Test
- public void testGetThruDate() {
- log.info("getThruDate");
- }
-
/** Test of getMonths method, of class PeriodDates. */
@Test
public void testGetMonths() {
- log.info("getMonths");
-
// Prepare two calendars with time not equals to 0
Calendar cal1 = DateUtil.getDefaultCalendar(new Date());
cal1.set(Calendar.DAY_OF_MONTH, 3);
@@ -167,64 +100,26 @@
}
}
- /** Test of getFormatedMonths method, of class PeriodDates. */
- //@Test
- public void testGetFormatedMonths() {
- log.info("getFormatedMonths");
- }
+ @Ignore("to be done as described in issue #1634")
+ @Test(timeout = 60 * 1000)
+ public void whatIfPeriodDatesIsNotInChronologicalOrder() {
+ Date january = DateUtil.createDate(1, 1, 2011);
+ Date december = DateUtil.createDate(1, 12, 2011);
- /** Test of beforeEnd method, of class PeriodDates. */
- //@Test
- public void testBeforeEnd_Calendar() {
- log.info("beforeEnd");
- }
+ // trying to break PeriodDates by creating an anti-chronological period
+ try {
+ PeriodDates periodDates = new PeriodDates(december, january);
+ Assert.fail();
+ } catch (IllegalArgumentException e) {
+ // as expected
+ }
- /** Test of afterEnd method, of class PeriodDates. */
- //@Test
- public void testAfterEnd_Calendar() {
- log.info("afterEnd");
+ // got ya!
+ PeriodDates periodDates = new PeriodDates();
+ periodDates.setFromDate(december);
+ periodDates.setThruDate(january);
+ periodDates.getMonths(); // infinite loop !
}
- /** Test of afterBegin method, of class PeriodDates. */
- //@Test
- public void testAfterBegin_Calendar() {
- log.info("afterBegin");
- }
- /** Test of between method, of class PeriodDates. */
- //@Test
- public void testBetween_Calendar() {
- log.info("between");
- }
-
- /** Test of beforeEnd method, of class PeriodDates. */
- //@Test
- public void testBeforeEnd_Date() {
- log.info("beforeEnd");
- }
-
- /** Test of afterEnd method, of class PeriodDates. */
- //@Test
- public void testAfterEnd_Date() {
- log.info("afterEnd");
- }
-
- /** Test of afterBegin method, of class PeriodDates. */
- //@Test
- public void testAfterBegin_Date() {
- log.info("afterBegin");
- }
-
- /** Test of between method, of class PeriodDates. */
- //@Test
- public void testBetween_Date() {
- log.info("between");
- }
-
- /** Test of toString method, of class PeriodDates. */
- //@Test
- public void testToString() {
- log.info("toString");
- }
-
}
1
0
17 Jul '11
Author: tchemit
Date: 2011-07-17 14:11:05 +0200 (Sun, 17 Jul 2011)
New Revision: 2153
Url: http://nuiton.org/repositories/revision/nuiton-utils/2153
Log:
Anomalie #1632: Resource.getURLs is not working under windows
Modified:
trunk/nuiton-utils/src/main/java/org/nuiton/util/Resource.java
Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/Resource.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/Resource.java 2011-07-06 09:25:33 UTC (rev 2152)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/Resource.java 2011-07-17 12:11:05 UTC (rev 2153)
@@ -25,6 +25,7 @@
package org.nuiton.util;
+import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -32,7 +33,6 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
-import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
@@ -241,20 +241,22 @@
for (URL urlFile : arrayURL) {
// EC-20100510 this cause wrong accent encoding
//String fileName = urlFile.getFile();
- String fileName;
- try {
- fileName = urlFile.toURI().getPath();
- } catch (Exception e) {
- if (log.isWarnEnabled()) {
- log.warn(e);
- }
- // warning, this can cause wrong encoding !!!
- fileName = urlFile.getFile();
- }
+// String fileName;
+// try {
+// fileName = urlFile.toURI().getPath();
+// } catch (Exception e) {
+// if (log.isWarnEnabled()) {
+// log.warn(e);
+// }
+// // warning, this can cause wrong encoding !!!
+// fileName = urlFile.getFile();
+// }
- // TODO deal with encoding in windows, this is very durty, but it
- // works...
- File file = new File(fileName.replaceAll("%20", " "));
+// // TODO deal with encoding in windows, this is very durty, but it
+// // works...
+ File file = FileUtils.toFile(urlFile);
+ String fileName = file.getAbsolutePath();
+// File file = new File(fileName.replaceAll("%20", " "));
if (!file.exists()) {
// this case should not appear
if (log.isDebugEnabled()) {
@@ -299,16 +301,16 @@
}
public static URL[] getClassPathURLsFromJarManifest(URL jarURL)
- throws IOException, URISyntaxException {
- JarFile jar = null;
+ throws IOException {
URL[] result;
+ File jarFile = FileUtils.toFile(jarURL);
+ if (log.isDebugEnabled()) {
+ log.debug("class-path jar to scan " + jarFile);
+ }
+ JarFile jar = new JarFile(jarFile);
try {
- String jarPath = jarURL.toURI().getPath();
- File jarFile = new File(jarPath);
- if (log.isDebugEnabled()) {
- log.debug("class-path jar to scan " + jarPath);
- }
- jar = new JarFile(jarFile);
+// String jarPath = jarURL.toURI().getPath();
+// File jarFile = new File(jarPath);
File container = jarFile.getParentFile();
Manifest mf = jar.getManifest();
String classPath = null;
@@ -343,7 +345,7 @@
}
result[i + 1] = path.toURI().toURL();
}
- jar.close();
+// jar.close();
} finally {
if (jar != null) {
jar.close();
@@ -358,38 +360,46 @@
log.trace("search '" + pattern + "' in " + zipFile);
}
- ArrayList<URL> result = new ArrayList<URL>();
- InputStream in = new FileInputStream(zipFile);
- ZipInputStream zis = new ZipInputStream(in);
- while (zis.available() != 0) {
- ZipEntry entry = zis.getNextEntry();
+ List<URL> result = new ArrayList<URL>();
+// InputStream in = new FileInputStream(zipFile);
+ ZipInputStream zis =
+ new ZipInputStream(new FileInputStream(zipFile));
+ try {
+ while (zis.available() != 0) {
+ ZipEntry entry = zis.getNextEntry();
- if (entry == null) {
- break;
- }
+ if (entry == null) {
+ break;
+ }
- String name = entry.getName();
- if (log.isTraceEnabled()) {
- log.trace("zipFile: " + zipFile + " name: " + name);
- }
- if (pattern == null || name.matches(pattern)) {
- // on recupere le fichier correspondant au pattern dans le
- // classloader
- URL url = getURL(name);
- // on ajoute le fichier correspondant au pattern dans la
- // liste
+ String name = entry.getName();
if (log.isTraceEnabled()) {
- log.trace("zipFile: " + zipFile + " url: " + url);
+ log.trace("zipFile: " + zipFile + " name: " + name);
}
- result.add(url);
+ if (pattern == null || name.matches(pattern)) {
+ // on recupere le fichier correspondant au pattern dans
+ // le classloader
+ URL url = getURL(name);
+ // on ajoute le fichier correspondant au pattern dans
+ // la liste
+ if (log.isTraceEnabled()) {
+ log.trace("zipFile: " + zipFile + " url: " + url);
+ }
+ result.add(url);
+ }
}
+ } finally {
+ zis.close();
}
if (log.isTraceEnabled()) {
log.trace("found with pattern '" + pattern + "' : " + result);
}
return result;
} catch (IOException eee) {
- throw new ResourceException(_("nuitonutil.error.get.url.from.zip", zipFile.getAbsolutePath(), eee.getMessage()));
+ throw new ResourceException(_("nuitonutil.error.get.url.from.zip",
+ zipFile.getAbsolutePath(),
+ eee.getMessage())
+ );
}
}
@@ -400,37 +410,45 @@
}
List<URL> result = new ArrayList<URL>();
- InputStream in = new FileInputStream(jarfile);
- ZipInputStream zis = new ZipInputStream(in);
- while (zis.available() != 0) {
- ZipEntry entry = zis.getNextEntry();
+// InputStream in = new FileInputStream(jarfile);
+ ZipInputStream zis =
+ new ZipInputStream(new FileInputStream(jarfile));
+ try {
+ while (zis.available() != 0) {
+ ZipEntry entry = zis.getNextEntry();
- if (entry == null) {
- break;
- }
+ if (entry == null) {
+ break;
+ }
- String name = entry.getName();
- if (log.isTraceEnabled()) {
- log.trace("jarfile: " + jarfile + " name: " + name);
- }
- if (pattern == null || name.matches(pattern)) {
- // on recupere le fichier correspondant au pattern dans le
- // classloader
- URL url = getURL(name);
- // on ajoute le fichier correspondant au pattern dans la
- // liste
+ String name = entry.getName();
if (log.isTraceEnabled()) {
- log.trace("jarfile: " + jarfile + " url: " + url);
+ log.trace("jarfile: " + jarfile + " name: " + name);
}
- result.add(url);
+ if (pattern == null || name.matches(pattern)) {
+ // on recupere le fichier correspondant au pattern
+ // dans le classloader
+ URL url = getURL(name);
+ // on ajoute le fichier correspondant au pattern dans
+ // la liste
+ if (log.isTraceEnabled()) {
+ log.trace("jarfile: " + jarfile + " url: " + url);
+ }
+ result.add(url);
+ }
}
+ } finally {
+ zis.close();
}
if (log.isTraceEnabled()) {
log.trace("found with pattern '" + pattern + "' : " + result);
}
return result;
} catch (IOException eee) {
- throw new ResourceException(_("nuitonutil.error.get.url.from.zip", jarfile.getAbsolutePath(), eee.getMessage()));
+ throw new ResourceException(_("nuitonutil.error.get.url.from.zip",
+ jarfile.getAbsolutePath(),
+ eee.getMessage())
+ );
}
}
@@ -485,7 +503,11 @@
}
return urlList;
} catch (MalformedURLException eee) {
- throw new ResourceException(_("nuitonutil.error.convert.file.to.url", repository + " (pattern " + pattern + ") ", eee.getMessage()));
+ throw new ResourceException(
+ _("nuitonutil.error.convert.file.to.url",
+ repository + " (pattern " + pattern + ") ",
+ eee.getMessage())
+ );
//throw new ResourceException("Le fichier n'a pu être converti en URL", eee);
}
}
@@ -555,9 +577,11 @@
* @throws IOException if any io pb
*/
public static boolean containsDirectDirectory(URL url, String directory) throws IOException {
- String fileName = url.getFile();
- // TODO deal with encoding in windows, this is very durty, but it works...
- File file = new File(fileName.replaceAll("%20", " "));
+// String fileName = url.getFile();
+// // TODO deal with encoding in windows, this is very durty, but it works...
+// File file = new File(fileName.replaceAll("%20", " "));
+ File file = FileUtils.toFile(url);
+ String fileName = file.getAbsolutePath();
if (!file.exists()) {
return false;
}
@@ -566,7 +590,12 @@
if (log.isTraceEnabled()) {
log.trace("zip to search " + file);
}
- return new ZipFile(file).getEntry(directory + '/') != null;
+ ZipFile zipFile = new ZipFile(file);
+ try {
+ return zipFile.getEntry(directory + '/') != null;
+ } finally {
+ zipFile.close();
+ }
}
if (file.isDirectory()) {
// cas ou le ichier du classLoader est un repertoire
1
0
Author: athimel
Date: 2011-07-06 11:25:33 +0200 (Wed, 06 Jul 2011)
New Revision: 2152
Url: http://nuiton.org/repositories/revision/nuiton-utils/2152
Log:
Avoid too long lines
Modified:
trunk/pom.xml
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2011-06-21 11:00:42 UTC (rev 2151)
+++ trunk/pom.xml 2011-07-06 09:25:33 UTC (rev 2152)
@@ -22,7 +22,9 @@
<http://www.gnu.org/licenses/lgpl-3.0.html>.
#L%
-->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
1
0
r2151 - in trunk/nuiton-utils: . src/main/java/org/nuiton/util src/test/java/org/nuiton/util
by bpoussin@users.nuiton.org 21 Jun '11
by bpoussin@users.nuiton.org 21 Jun '11
21 Jun '11
Author: bpoussin
Date: 2011-06-21 13:00:42 +0200 (Tue, 21 Jun 2011)
New Revision: 2151
Url: http://nuiton.org/repositories/revision/nuiton-utils/2151
Log:
Implantation de Map multikey en se basant sur le code des matrix (test a ameliorer/faire)
(commit pour ne pas perdre le travail)
Added:
trunk/nuiton-utils/src/main/java/org/nuiton/util/MatrixMap.java
trunk/nuiton-utils/src/test/java/org/nuiton/util/MatrixMapTest.java
Modified:
trunk/nuiton-utils/pom.xml
Modified: trunk/nuiton-utils/pom.xml
===================================================================
--- trunk/nuiton-utils/pom.xml 2011-06-16 08:31:43 UTC (rev 2150)
+++ trunk/nuiton-utils/pom.xml 2011-06-21 11:00:42 UTC (rev 2151)
@@ -41,6 +41,11 @@
<dependencies>
<dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ </dependency>
+
+ <dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</dependency>
Added: trunk/nuiton-utils/src/main/java/org/nuiton/util/MatrixMap.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/MatrixMap.java (rev 0)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/MatrixMap.java 2011-06-21 11:00:42 UTC (rev 2151)
@@ -0,0 +1,2296 @@
+package org.nuiton.util;
+
+import java.io.Serializable;
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.RandomAccess;
+import org.apache.commons.lang.ObjectUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Permet de stocker des informations dans une matrix a N dimension
+ * Si lors de l'ajout on indique une dimension qui n'existe pas encore ou
+ * un element dans une dimension qui n'existe pas, la matrice ajoute
+ * automatiquement les elements manquant pour que l'ajout se passe bien.
+ * <p>
+ * MatrixMap permet de stocker les elements avec des cles de n'importe quel
+ * type. Les coordonnees utilisant ces objets sont converti en coordonnees
+ * numeriques qui est la seul chose que sait gere Matrix. Ces coordonnees
+ * numeriques sont alors convertis en coordonnees lineaire pour le stockage
+ * dans Vector. On decoupe ainsi les problemes et on minimise le stockage et
+ * certain traitement sur les données puisqu'au final toutes les données sont
+ * dans une simple liste.
+ * <p>
+ * Pour créer une nouvelle matrice, il faut utiliser une des méthodes de
+ * {@link MatrixMap#Factory}
+ *
+ * @author poussin
+ * @version $Revision$
+ * @since 2.2.1
+ *
+ * Last update: $Date$
+ * by : $Author$
+ */
+public interface MatrixMap<E> extends Iterable<E> {
+
+ /**
+ * Classe permettant la creation de matrice
+ */
+ static public class Factory {
+ static public <T> MatrixMap<T> create(List ... semantics) {
+ MatrixMap<T> result = new MatrixMapFixed<T>(semantics);
+ return result;
+ }
+
+ static public <T> MatrixMap<T> create(String name, List... semantics) {
+ MatrixMap<T> result = new MatrixMapFixed<T>(name, semantics);
+ return result;
+ }
+
+ static public <T> MatrixMap<T> create(String name, String[] dimNames, List... semantics) {
+ MatrixMap<T> result = new MatrixMapFixed<T>(name, dimNames, semantics);
+ return result;
+ }
+
+ static public <T> MatrixMap<T> create(MatrixMap<T> matrix) {
+ MatrixMap<T> result = new MatrixMapFixed<T>(matrix);
+ return result;
+ }
+
+ static public <T> MatrixMap<T> createElastic(List ... semantics) {
+ MatrixMap<T> result = create(semantics);
+ result = createElastic(result);
+ return result;
+ }
+
+ static public <T> MatrixMap<T> createElastic(String name, List... semantics) {
+ MatrixMap<T> result = create(name, semantics);
+ result = createElastic(result);
+ return result;
+ }
+
+ static public <T> MatrixMap<T> createElastic(String name, String[] dimNames, List... semantics) {
+ MatrixMap<T> result = create(name, dimNames, semantics);
+ result = createElastic(result);
+ return result;
+ }
+
+ static public <T> MatrixMap<T> createElastic(MatrixMap<T> matrix) {
+ MatrixMap<T> result = new MatrixMapElastic<T>(matrix);
+ return result;
+ }
+ }
+
+ @Override
+ public MatrixMapIterator<E> iterator();
+
+ /**
+ * Copy la matrice pour pouvoir la modifier sans perdre les donnees
+ * initiales.
+ *
+ * @return new matrix
+ */
+ public MatrixMap<E> copy();
+
+ public SemanticList[] getSemantics();
+
+ public SemanticList getSemantic(int dim);
+
+ public void setSemantic(int dim, List sem);
+
+ public void setName(String name);
+
+ public String getName();
+
+ public String[] getDimensionNames();
+
+ public void setDimensionNames(String[] names);
+
+ public void setDimensionName(int dim, String name);
+
+ public String getDimensionName(int dim);
+
+ public int getDimCount();
+
+ public int[] getDim();
+
+ public int getDim(int d);
+
+ /**
+ * Applique sur chaque element de la matrice la fonction f
+ *
+ * @param f la fonction a appliquer
+ * @return Retourne la matrice elle meme. Les modifications sont faites directement
+ * dessus
+ */
+ public MatrixMap<E> map(MapFunction<E> f);
+
+ /**
+ * Retourne l'element a une certaine position en utilisant des indices
+ * ex: 2,3,1
+ * @param coordinates
+ * @return
+ */
+ public E getValueIndex(int ... coordinates);
+
+ /**
+ * Modifie l'element a une certaine position en utilisant des indices
+ * ex: 2,3,1
+ * @param value la nouvelle valeur
+ * @param coordinates
+ * @return
+ */
+ public void setValueIndex(E value, int ... coordinates);
+
+ /**
+ * Retourne l'element a une certaine position en utilisant les semantiques
+ *
+ * @param coordinates
+ * @return
+ */
+ public E getValue(Object ... coordinates);
+
+ /**
+ * Modifie l'element a une certaine position en utilisant les semantiques
+ *
+ * @param value la nouvelle valeur
+ * @param coordinates
+ * @return
+ */
+ public void setValue(E value, Object ... coordinates);
+
+ /**
+ * Verifie que deux matrices sont completement equals
+ * (dimension, semantique, nom, valeur, ...)
+ * @param mat
+ * @return
+ */
+ public boolean equals(MatrixMap mat);
+
+ /**
+ * Verifie si les matrices sont egales en ne regardant que les valeurs et
+ * pas les semantiques
+ *
+ * @param mat
+ * @return equality on values
+ */
+ public boolean equalsValues(MatrixMap<E> mat);
+
+ /**
+ * Representation string de la matrice quelque soit le nombre de dimension
+ * @return
+ */
+ public String toStringGeneric();
+
+ /**
+ * Indique si les semantiques passées en argument sont valable pour la
+ * matrice courante
+ *
+ * @param semantics
+ * @return
+ */
+ public boolean isValidCoordinates(Object[] semantics);
+
+ /**
+ * Copie une matrice dans la matrice actuelle. La matrice à copier à le même
+ * nombre de dimension. Si la matrice à copier est trop grande seul les
+ * éléments pouvant être copier le seront.
+ *
+ * @param mat la matrice à copier
+ * @return return la matrice courante.
+ */
+ public MatrixMap paste(MatrixMap<E> mat);
+
+ /**
+ * Permet de prendre une sous matrice dans la matrice courante. La sous
+ * matrice a le même nombre de dimensions mais sur une des dimensions on ne
+ * prend que certain élément.
+ *
+ * @param dim la dimension dans lequel on veut une sous matrice
+ * @param start la position dans dim d'ou il faut partir pour prendre la
+ * sous matrice. 0 <= start < dim.size si start est négatif alors
+ * la position de départ est calculé par rapport à la fin de la
+ * dimension, pour avoir le dernier élément il faut passer -1
+ * @param nb le nombre d'élément à prendre dans la dimension si nb est
+ * inférieur ou égal à 0 alors cela indique qu'il faut prendre
+ * tous les éléments jusqu'à la fin de la dimension.
+ * @return new matrix
+ */
+ public MatrixMap<E> getSubMatrix(int dim, Object start, int nb);
+
+ /**
+ * Permet de prendre une sous matrice dans la matrice courante. La sous
+ * matrice a le même nombre de dimensions mais sur une des dimensions on ne
+ * prend que certain élément.
+ *
+ * @param dim la dimension dans lequel on veut une sous matrice
+ * @param elem les éléments dans la dimension à conserver
+ * @return new matrix
+ */
+ public MatrixMap<E> getSubMatrix(int dim, Object... elem);
+
+ /**
+ * Permet de prendre une sous matrice dans la matrice courante.
+ *
+ * Réalise plusieurs appels à {@link #getSubMatrix(int, Object...)} suivant
+ * l'implémentation.
+ *
+ * @param elem les éléments dans la dimension à conserver
+ * @return new matrix
+ */
+ public MatrixMap<E> getSubMatrix(Object[]... elems);
+
+ /**
+ * Reduit la matrice de sorte que toutes les dimensions qui n'ont qu'un
+ * élement soit supprimée. Au pire cette méthode retourne une matrice à une
+ * seule dimension à un seul élément.
+ *
+ * @return une nouvelle matrice plus petite que la matrice actuelle ou egal
+ * s'il n'y a aucune dimension à supprimer
+ */
+ public MatrixMap<E> reduce();
+
+ /**
+ * Reduit le matrice seulement sur les dimensions passées en argument. Si
+ * une des dimensions passées en arguement n'a pas qu'un seul élément, cette
+ * dimension n'est pas prise en compte.
+ *
+ * @param dims les dimensions sur lequel il faut faire la reduction
+ * @return une nouvelle matrice
+ */
+ public MatrixMap<E> reduceDims(int... dims);
+ /**
+ * Reduit la matrice de sorte que toutes les dimensions qui n'ont qu'un
+ * élement soit supprimée. Au pire cette méthode retourne une matrice à une
+ * seule dimension à un seul élément.
+ *
+ * @param minNbDim le nombre minimum de dimension que l'on souhaite pour la
+ * matrice résultat
+ * @return une nouvelle matrice plus petite que la matrice actuelle ou egal
+ * s'il n'y a aucune dimension à supprimer
+ */
+ public MatrixMap<E> reduce(int minNbDim);
+
+ /**
+ * Permet de retourner une nouvelle matrice ayant les semantiques passées
+ * en parametre. La nouvelle matrice contient les données de l'ancienne
+ * matrice par copie en fonction des semantiques
+ *
+ * @param sems
+ * @return
+ */
+ public MatrixMap<E> extend(Object... sems);
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // C L A S S E I N T E R N E
+ //
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Classe contenant des méthodes statiques pour aider a la manipulation
+ * des matrices
+ */
+ static public class MatrixHelper {
+
+ /**
+ * Mais en forme un texte pour qu'il fasse exactement la longueur
+ * demandee (length). Si length est possitif alors s'il y besoin
+ * d'ajouter des espaces, ils seront mis devant le texte, sinon il
+ * seront mis apres le texte
+ *
+ * @param o l'objet a convertir en string
+ * @param length la longueur de representation souhaite
+ * @param valueIfNull la valeur a utilise si l'objet est null
+ * @return
+ */
+ public static String format(Object o, int length, String valueIfNull) {
+ if (o == null) {
+ o = valueIfNull;
+ }
+ int absLength = Math.abs(length);
+
+ String result = String.valueOf(o);
+ if (absLength > 3) {
+ result = StringUtils.abbreviate(result, absLength);
+ }
+ if (length < 0) {
+ result = StringUtils.leftPad(result, absLength);
+ } else if (length > 0) {
+ result = StringUtils.rightPad(result, absLength);
+ }
+
+ return result;
+ }
+
+ /**
+ * Permet de convertir des coordonnées définies par des entiers en coordonnées
+ * semantique par des objets
+ *
+ * @param semantics la semantique à utilisé pour la conversion
+ * @param coordinates les coordonnées à convertir
+ * @return un tableau donnant les coordonnées sous forme semantique s'il n'y
+ * a pas de semantique (liste pleine de null) alors un objet Integer
+ * est créer pour représenter la semantique de la dimension.
+ */
+ public static Object[] dimensionToSemantics(List[] semantics,
+ int[] coordinates) {
+ Object[] result = new Object[coordinates.length];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = semantics[i].get(coordinates[i]);
+ }
+ return result;
+ }
+
+ /**
+ * Permet de convertir des coordonnées sémantiques en coordonnées défini par
+ * des entiers. Cette fonction est l'inverse de
+ * {@link #dimensionToSemantics}.
+ *
+ * @param semantics la semantique à utiliser pour la conversion
+ * @param coordinates les coordonnées sémantique
+ * @return les coordonnées en entier.
+ */
+ public static int[] semanticsToDimension(List[] semantics,
+ Object[] coordinates) {
+ int[] result = new int[coordinates.length];
+ for (int i = 0; i < coordinates.length; i++) {
+ result[i] = indexOf(semantics, i, coordinates[i]);
+ }
+ return result;
+ }
+
+ /**
+ * Permet de retrouver la position d'un objet dans une liste
+ *
+ * @param semantics la semantique à utilisé pour la recherche
+ * @param dim la dimension dans lequel il faut faire la recherche
+ * @param o l'objet à rechercher
+ * @return la position de l'objet dans la dimension demandée
+ *
+ * @throws NoSuchElementException If element doesn't exists
+ */
+ public static int indexOf(List[] semantics, int dim, Object o)
+ throws NoSuchElementException {
+ int result = -1;
+ if ((0 <= dim) && (dim < semantics.length)) {
+ result = semantics[dim].indexOf(o);
+ }
+ if (result == -1) {
+ throw new NoSuchElementException(
+ "L'objet passé en argument n'a pas été retrouvé ou la dimension donnée ne convient pas:"
+ + o + " in " + semantics[dim]);
+ }
+ return result;
+ }
+
+ /**
+ * Permet de savoir si deux dimension sont identiques.
+ *
+ * @param dim1 first dimensions
+ * @param dim2 second dimensions
+ * @return dimension equality
+ */
+ public static boolean sameDimension(int[] dim1, int[] dim2) {
+ return Arrays.equals(dim1, dim2);
+ }
+
+ }
+
+ /**
+ * Iterateur de matrice
+ *
+ * @param <E>
+ */
+ static public interface MatrixMapIterator<E> extends Iterator<E> {
+ public int[] getCoordinates();
+ public E getValue();
+ public void setValue(E value);
+ public Object[] getSemanticsCoordinates();
+ }
+
+ static public class MatrixMapIteratorImpl<E> implements MatrixMapIterator<E> { // MatrixMapIteratorImpl
+
+ protected MatrixIterator<E> iterator = null;
+ protected List[] semantics = null;
+ protected int pos = 0;
+
+ /**
+ * @param iterator la matrice sur lequel l'iterator doit travailler
+ * @param semantics la semantique de matrix, si matrix n'a pas de semantique
+ * alors il faut passer null
+ */
+ public MatrixMapIteratorImpl(MatrixIterator<E> iterator, List[] semantics) {
+ this.iterator = iterator;
+ this.semantics = semantics;
+ pos = 0;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public E next() {
+ return iterator.next();
+ }
+
+ @Override
+ public void remove() {
+ iterator.remove();
+ }
+
+ public int[] getCoordinates() {
+ return iterator.getCoordinates();
+ }
+
+ public E getValue() {
+ return iterator.getValue();
+ }
+
+ public void setValue(E value) {
+ iterator.setValue(value);
+ }
+
+ public Object[] getSemanticsCoordinates() {
+ Object[] result = null;
+ if (semantics != null) {
+ int[] coordinates = getCoordinates();
+ result = MatrixHelper.dimensionToSemantics(semantics,
+ coordinates);
+ }
+ return result;
+ }
+
+ } // MatrixMapIteratorImpl
+
+ /**
+ * Collection particuliere utilisee pour la stockage des semantiques.
+ * <p>
+ * Sert a optimiser la recherche de la position d'une donnee dans la liste.
+ * Permet aussi de verifier qu'on ajoute pas de doublon dans la liste
+ *
+ * @param <T>
+ */
+ public static class SemanticList<T> extends AbstractList<T> implements RandomAccess {
+
+ protected ArrayList<T> datas = null;
+ protected Map<T, Integer> index = new HashMap<T, Integer>();
+
+ public SemanticList() {
+ this(new ArrayList<T>());
+ }
+
+ public SemanticList(Collection<T> c) {
+ datas = new ArrayList<T>(c);
+ }
+
+ /*
+ * @see java.util.AbstractList#get(int)
+ */
+ @Override
+ public T get(int index) {
+ T result = datas.get(index);
+ return result;
+ }
+
+ @Override
+ public void add(int index, T element) {
+ datas.add(index, element);
+ this.index.clear();
+ }
+
+ @Override
+ public T set(int index, T element) {
+ T result = datas.set(index, element);
+ this.index.clear();
+ return result;
+ }
+
+ @Override
+ public T remove(int index) {
+ T result = super.remove(index);
+ this.index.clear();
+ return result;
+ }
+
+
+ /*
+ * @see java.util.AbstractCollection#size()
+ */
+ @Override
+ public int size() {
+ int result = datas.size();
+ return result;
+ }
+
+ /*
+ * @see java.util.AbstractList#indexOf(java.lang.Object)
+ */
+ @Override
+ public int indexOf(Object o) {
+ Map<T, Integer> index = getIndex();
+ Integer result = index.get(o);
+ int resultIndex = -1;
+ if (result != null) {
+ resultIndex = result.intValue();
+ }
+ return resultIndex;
+ }
+
+ protected Map<T, Integer> getIndex() {
+ if (index.isEmpty()) {
+ for (int i = 0; i < datas.size(); i++) {
+ index.put(datas.get(i), Integer.valueOf(i));
+ }
+ }
+ return index;
+ }
+ }
+
+ /**
+ * Implantation particuliere de matrice, qui lorsqu'on lui passe des
+ * dimension qui n'existe pas, elle les ajoutes dans les semantiques. Ceci
+ * n'est vrai que pour le set avec des semantiques, le set avec des indices
+ * ne rend pas la matrice elastique.
+ * <p>
+ * Cette classe fonctionne avec une matrice interne que l'on change lorsque
+ * l'on a besoin de modifier les dimensions. Le changement de dimension
+ * a donc un cout (creation d'une nouvelle matrice, copie des elements)
+ * <p>
+ * Si on cree une sous matrice, et que l'on modifie la matrice mere
+ * La sous matrice n'est pas impacter, puisqu'elle est base sur l'ancienne
+ * represention interne de la matrice elastique, les deux matrices n'ont donc
+ * plus de lien.
+ * <p>
+ * Les methodes reduce et extend retourne de nouvelle matrice qui ne sont
+ * pas elastique. Si on veut qu'elle le soit, il faut les reencapsuler
+ *
+ * @param <E>
+ */
+ static public class MatrixMapElastic<E> implements MatrixMap<E> {
+
+ protected MatrixMap<E> internalMatrixMap;
+
+ public MatrixMapElastic() {
+ internalMatrixMap = Factory.create();
+ }
+
+ public MatrixMapElastic(MatrixMap<E> m) {
+ setInternalMatrixMap(m);
+ }
+
+ public MatrixMap<E> getInternalMatrixMap() {
+ return internalMatrixMap;
+ }
+
+ public void setInternalMatrixMap(MatrixMap<E> internalMatrixMap) {
+ this.internalMatrixMap = internalMatrixMap;
+ }
+
+ public MatrixMapIterator<E> iterator() {
+ return getInternalMatrixMap().iterator();
+ }
+
+ public MatrixMap<E> copy() {
+ return getInternalMatrixMap().copy();
+ }
+
+ public SemanticList[] getSemantics() {
+ return getInternalMatrixMap().getSemantics();
+ }
+
+ public SemanticList getSemantic(int dim) {
+ return getInternalMatrixMap().getSemantic(dim);
+ }
+
+ public void setSemantic(int dim, List sem) {
+ getInternalMatrixMap().setSemantic(dim, sem);
+ }
+
+ public void setName(String name) {
+ getInternalMatrixMap().setName(name);
+ }
+
+ public String getName() {
+ return getInternalMatrixMap().getName();
+ }
+
+ public String[] getDimensionNames() {
+ return getInternalMatrixMap().getDimensionNames();
+ }
+
+ public void setDimensionNames(String[] names) {
+ getInternalMatrixMap().setDimensionNames(names);
+ }
+
+ public void setDimensionName(int dim, String name) {
+ getInternalMatrixMap().setDimensionName(dim, name);
+ }
+
+ public String getDimensionName(int dim) {
+ return getInternalMatrixMap().getDimensionName(dim);
+ }
+
+ public int getDimCount() {
+ return getInternalMatrixMap().getDimCount();
+ }
+
+ public int[] getDim() {
+ return getInternalMatrixMap().getDim();
+ }
+
+ public int getDim(int d) {
+ return getInternalMatrixMap().getDim(d);
+ }
+
+ public MatrixMap<E> map(MapFunction<E> f) {
+ return getInternalMatrixMap().map(f);
+ }
+
+ public E getValueIndex(int... coordinates) {
+ return getInternalMatrixMap().getValueIndex(coordinates);
+ }
+
+ public void setValueIndex(E value, int... coordinates) {
+ // la matrice est elastique que pour le set avec des semantics
+ getInternalMatrixMap().setValueIndex(value, coordinates);
+ }
+
+ public E getValue(Object... coordinates) {
+ return getInternalMatrixMap().getValue(coordinates);
+ }
+
+ public void setValue(E value, Object... coordinates) {
+ // check si les coordonnees sont valide.
+ // si non valide alors on extend la matrice interne
+ // et on appelle sur la nouvelle matrice interne
+ if (!isValidCoordinates(coordinates)) {
+ MatrixMap<E> newMatrixMap = getInternalMatrixMap().extend(coordinates);
+ setInternalMatrixMap(newMatrixMap);
+ }
+ getInternalMatrixMap().setValue(value, coordinates);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return getInternalMatrixMap().equals(obj);
+ }
+
+ public boolean equals(MatrixMap mat) {
+ return getInternalMatrixMap().equals(mat);
+ }
+
+ public boolean equalsValues(MatrixMap<E> mat) {
+ return getInternalMatrixMap().equalsValues(mat);
+ }
+
+ @Override
+ public String toString() {
+ return getInternalMatrixMap().toString();
+ }
+
+ public String toStringGeneric() {
+ return getInternalMatrixMap().toStringGeneric();
+ }
+
+ public boolean isValidCoordinates(Object[] semantics) {
+ return getInternalMatrixMap().isValidCoordinates(semantics);
+ }
+
+ public MatrixMap paste(MatrixMap<E> mat) {
+ return getInternalMatrixMap().paste(mat);
+ }
+
+ public MatrixMap<E> getSubMatrix(int dim, Object start, int nb) {
+ return getInternalMatrixMap().getSubMatrix(dim, start, nb);
+ }
+
+ public MatrixMap<E> getSubMatrix(int dim, Object... elem) {
+ return getInternalMatrixMap().getSubMatrix(dim, elem);
+ }
+
+ public MatrixMap<E> getSubMatrix(Object[]... elems) {
+ return getInternalMatrixMap().getSubMatrix(elems);
+ }
+
+ public MatrixMap<E> reduce() {
+ return getInternalMatrixMap().reduce();
+ }
+
+ public MatrixMap<E> reduceDims(int... dims) {
+ return getInternalMatrixMap().reduceDims(dims);
+ }
+
+ public MatrixMap<E> reduce(int minNbDim) {
+ return getInternalMatrixMap().reduce(minNbDim);
+ }
+
+ public MatrixMap<E> extend(Object... sems) {
+ return getInternalMatrixMap().extend(sems);
+ }
+
+ }
+
+ /**
+ * Implantation de MatrixMap dont les dimensions sont fixees a la creation
+ * Les dimensions ne change plus par la suite
+ */
+ static public class MatrixMapFixed<E> extends AbstractMatrixMap<E> {
+ /** to use log facility, just put in your code: log.info(\"...\"); */
+ static private Log log = LogFactory.getLog(MatrixMapFixed.class);
+
+ protected Matrix<E> matrix = null;
+
+ public MatrixMapFixed(List ... semantics) {
+ super(semantics);
+ }
+
+ public MatrixMapFixed(String name, List... semantics) {
+ this(semantics);
+ setName(name);
+ }
+
+ public MatrixMapFixed(String name, String[] dimNames, List... semantics) {
+ this(name, semantics);
+ for (int i = 0; dimNames != null && i < dimNames.length; i++) {
+ setDimensionName(i, dimNames[i]);
+ }
+ }
+
+ public MatrixMapFixed(MatrixMap<E> matrix) {
+ this(matrix.getName(), matrix.getDimensionNames(), matrix.getSemantics());
+ this.pasteIndex(matrix);
+ }
+
+ protected Matrix<E> getMatrix(){
+ if (matrix == null) {
+ matrix = new Matrix<E>(getDim());
+ }
+ return matrix;
+ }
+
+ @Override
+ public MatrixMapIterator<E> iterator() {
+ return new MatrixMapIteratorImpl<E>(getMatrix().iterator(), getSemantics());
+ }
+
+ @Override
+ public MatrixMap<E> map(MapFunction<E> f) {
+ getMatrix().data.map(f);
+ return this;
+ }
+
+ @Override
+ public E getValueIndex(int ... coordinates) {
+ if (coordinates.length == 0) {
+ throw new IllegalArgumentException("Coordinates must not be empty");
+ }
+ return getMatrix().getValue(coordinates);
+ }
+
+ /**
+ * Modifie un element de la matrice en fonction des dimensions passé en
+ * paramètre.<br>
+ *
+ * Exemple: Si on a un matrice 3D.<br>
+ * m.set(v, [1,1,1]) modifie un element de la matrice.<br>
+ *
+ * @param dimensions les différentes dimension à extraire.
+ *
+ * @param d l'entier double qui doit remplacer l'entier double spécifié par
+ * l'argument dimensions
+ */
+ @Override
+ public void setValueIndex(E value, int ... coordinates) {
+ if (coordinates.length == 0) {
+ throw new IllegalArgumentException("Coordinates must not be empty");
+ }
+ getMatrix().setValue(coordinates, value);
+ }
+
+ /**
+ * Copie une matrice dans la matrice actuelle. La matrice à copier à le même
+ * nombre de dimension. Si la matrice à copier est trop grande seul les
+ * éléments pouvant être copier le seront.
+ *
+ * @param origin le point à partir duquel il faut faire la copie
+ * @param mat la matrice à copier
+ * @return return la matrice courante.
+ */
+ public MatrixMap<E> paste(int[] origin, MatrixMap<E> mat) {
+ if (mat != null) {
+ // si les matrice mat et this on les memes dimensions
+ // et que origin est 0, on optimise en appeler une methode paste
+ // sur Matrix qui l'appel sur le vector
+
+ // permet de savoir si l'origin est bien le point 0 de la matrice
+ boolean origin0 = true;
+ for (int i = 0; i < origin.length && origin0; i++) {
+ origin0 = origin0 && origin[i] == 0;
+ }
+ if (origin0
+ && mat instanceof MatrixMapFixed
+ && Arrays.equals(mat.getDim(), this.getDim())) {
+ getMatrix().data.paste(((MatrixMapFixed<E>)mat).getMatrix().data);
+ } else {
+ super.paste(origin, mat);
+ }
+ }
+ return this;
+ }
+
+ }
+
+ /**
+ * Classe abstraite permettant de facilement implanter les matrice fixe,
+ * elastique et submatrix
+ *
+ * @param <E>
+ */
+ static public abstract class AbstractMatrixMap<E> implements MatrixMap<E> {
+
+ /** to use log facility, just put in your code: log.info(\"...\"); */
+ static private Log log = LogFactory.getLog(AbstractMatrixMap.class);
+
+ protected String name = null;
+
+ protected String[] dimNames = null;
+
+ protected int[] dim = null;
+
+ protected SemanticList[] semantics = null;
+
+ protected void init(int[] dim) {
+ this.dim = new int[dim.length];
+ System.arraycopy(dim, 0, this.dim, 0, dim.length);
+ semantics = new SemanticList[dim.length];
+ dimNames = new String[dim.length];
+ }
+
+ protected AbstractMatrixMap(int[] dim) {
+ init(dim);
+ for (int i = 0; i < getDimCount(); i++) {
+ // par defaut les listes des semantiques contiennent des nulls
+ // FIXME no multiple null allowed
+ setSemantic(i, Collections.nCopies(dim[i], null));
+ }
+ }
+
+ public AbstractMatrixMap(List ... semantics) {
+ int[] dim = new int[semantics.length];
+ for (int i = 0; i < dim.length; i++) {
+ if (semantics[i] == null) {
+ dim[i] = 0;
+ } else {
+ dim[i] = semantics[i].size();
+ }
+ }
+ init(dim);
+ for (int i = 0; i < getDimCount(); i++) {
+ setSemantic(i, semantics[i]);
+ }
+ }
+
+ protected AbstractMatrixMap(String name, int[] dim) {
+ this(dim);
+ setName(name);
+ }
+
+ protected AbstractMatrixMap(String name, int[] dim, String[] dimNames) {
+ this(dim);
+ setName(name);
+ for (int i = 0; dimNames != null && i < dimNames.length; i++) {
+ setDimensionName(i, dimNames[i]);
+ }
+ }
+
+ public AbstractMatrixMap(String name, List... semantics) {
+ this(semantics);
+ setName(name);
+ }
+
+ public AbstractMatrixMap(String name, String[] dimNames, List... semantics) {
+ this(name, semantics);
+ for (int i = 0; dimNames != null && i < dimNames.length; i++) {
+ setDimensionName(i, dimNames[i]);
+ }
+ }
+
+ public AbstractMatrixMap(MatrixMap<E> matrix) {
+ this(matrix.getName(), matrix.getDimensionNames(), matrix.getSemantics());
+ this.pasteIndex(matrix);
+ }
+
+ /**
+ * Copy la matrice pour pouvoir la modifier sans perdre les donnees
+ * initiales.
+ *
+ * @return new matrix
+ */
+ public MatrixMap<E> copy() {
+ MatrixMap<E> result = new MatrixMapFixed<E>(this);
+ return result;
+ }
+
+ /*
+ * @see java.lang.Object#clone()
+ */
+ @Override
+ public MatrixMap clone() {
+ return copy();
+ }
+
+ public SemanticList[] getSemantics() {
+ return semantics;
+ }
+
+ public SemanticList getSemantic(int dim) {
+ return semantics[dim];
+ }
+
+ public void setSemantic(int dim, List sem) {
+ // make copy because this matrix can change semantics
+ SemanticList l = new SemanticList(sem);
+ semantics[dim] = l;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String[] getDimensionNames() {
+ return dimNames;
+ }
+
+ public void setDimensionNames(String[] names) {
+ for (int i = 0; names != null && i < names.length; i++) {
+ setDimensionName(i, names[i]);
+ }
+ }
+
+ public void setDimensionName(int dim, String name) {
+ dimNames[dim] = name;
+ }
+
+ public String getDimensionName(int dim) {
+ return dimNames[dim];
+ }
+
+ public int getDimCount() {
+ return dim.length;
+ }
+
+ public int[] getDim() {
+ return dim;
+ }
+
+ public int getDim(int d) {
+ return dim[d];
+ }
+
+ /**
+ * Retourne la matrice elle meme. Les modifications sont faites directement
+ * dessus
+ */
+ @Override
+ public MatrixMap<E> map(MapFunction<E> f) {
+ for (MatrixMapIterator<E> i = iterator(); i.hasNext();) {
+ i.setValue(f.apply(i.next()));
+ }
+ return this;
+ }
+
+ public E getValue(Object ... coordinates) {
+ if (coordinates.length == 0) {
+ throw new IllegalArgumentException("Coordinates must not be empty");
+ }
+ int[] intCoordinates =
+ MatrixHelper.semanticsToDimension(getSemantics(), coordinates);
+ E result = getValueIndex(intCoordinates);
+ return result;
+ }
+
+ public void setValue(E value, Object ... coordinates) {
+ if (coordinates.length == 0) {
+ throw new IllegalArgumentException("Coordinates must not be empty");
+ }
+ int[] intCoordinates =
+ MatrixHelper.semanticsToDimension(getSemantics(), coordinates);
+ setValueIndex(value, intCoordinates);
+ }
+
+ // TODO peut-etre faire une variante de equals qui regarde par rapport au
+ // coordonnées sémantique
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof MatrixMap && equals((MatrixMap) o);
+ }
+
+ public boolean equals(MatrixMap mat) {
+ boolean result = true;
+ // le nom doit être le même
+ result = result && getName().equals(mat.getName());
+
+ result = result && equalsValues(mat);
+
+ // les sémantiques doivent-être identique
+ for (int i = 0; result && i < getDimCount(); i++) {
+ String dimName1 = getDimensionName(i);
+ String dimName2 = mat.getDimensionName(i);
+ result = ObjectUtils.equals(dimName1, dimName2);
+ if (log.isTraceEnabled()) {
+ log.trace("dimName1(" + dimName1 + ")==dimName2(" + dimName2
+ + ")=" + result);
+ }
+ // System.out.println("dimName1("+dimName1+")==dimName2("+dimName2+
+ // ")="+result);
+
+ List sem1 = getSemantic(i);
+ List sem2 = mat.getSemantic(i);
+ result = result && ObjectUtils.equals(sem1, sem2);
+ if (log.isTraceEnabled()) {
+ log.trace("sem1(" + sem1 + ")==sem2(" + sem2 + ")=" + result);
+ }
+ // System.out.println("sem1("+sem1+")==sem1("+sem2+ ")="+result);
+ }
+
+ if (log.isTraceEnabled()) {
+ log.trace("result=" + result);
+ }
+ // System.out.println("result="+result);
+ return result;
+ }
+
+ /**
+ * Verifie si les matrices sont egales en ne regardant que les valeurs et
+ * pas les semantiques
+ *
+ * @param mat
+ * @return equality on values
+ */
+ public boolean equalsValues(MatrixMap mat) {
+ boolean result = true;
+ // les dimensions doivent-être identique
+ result = result && MatrixHelper.sameDimension(getDim(), mat.getDim());
+
+ // toutes les données doivent être identique
+ for (MatrixMapIterator<E> i = mat.iterator(); result && i.hasNext();) {
+ E v1 = i.next();
+ E v2 = getValueIndex(i.getCoordinates());
+ result = v1 == v2;
+ if (log.isTraceEnabled()) {
+ log.trace("v1(" + v1 + ")==v2(" + v2 + ")=" + result);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Si la matrice est 1D
+ * <pre>
+ * MaMatrice(matrix1D) [
+ * MaDimName: Dim1, Dim2, Dim3,
+ * v1, v2, v3
+ * ]
+ * </pre>
+ *
+ * Si la matrice est 2D
+ * <pre>
+ * MaMatrice(matrix2D) [
+ * MaDimX
+ * MaDimY Dim1, Dim2, Dim3,
+ * DimA v1, v2, v3
+ * DimB v4, v5, v6
+ * DimC v7, v8, v9
+ * ]
+ * </pre>
+ *
+ * Pour les autres types de matrice la methode {@link #toStringGeneric() }
+ * est utilise
+ *
+ * @return
+ */
+ @Override
+ public String toString() {
+ int LENGTH = 10;
+ StringBuilder result = new StringBuilder();
+ if (getDimCount() == 1) {
+ result.append(MatrixHelper.format(getName(), -LENGTH, "#NoNameMat"));
+ result.append("(matrix1D)[\n");
+ String dimName = getDimensionName(0);
+ result.append(MatrixHelper.format(dimName, LENGTH, "#NoNameDim"));
+ for (Object sem : getSemantic(0)) {
+ result.append(",");
+ result.append(MatrixHelper.format(sem, -LENGTH, null));
+ }
+ result.append(StringUtils.repeat(" ", LENGTH + 1));
+ for (int i = 0; i < getDim(0); i++) {
+ Object v = getValueIndex(i);
+ result.append(MatrixHelper.format(v, -LENGTH, null) + ",");
+ }
+ result.append("\n]");
+ } else if (getDimCount() == 2) {
+ int[] pos = new int[2];
+ result.append(MatrixHelper.format(getName(), -LENGTH, "#NoNameMat"));
+ result.append("(matrix2D) [\n");
+
+ result.append(StringUtils.repeat(" ", LENGTH + 1));
+ String dimNameX = getDimensionName(0);
+ result.append(MatrixHelper.format(dimNameX, LENGTH, "#DimX"));
+ result.append("\n");
+ String dimNameY = getDimensionName(1);
+ result.append(MatrixHelper.format(dimNameY, LENGTH, "#DimY"));
+ result.append(" ");
+ for (Object sem : getSemantic(0)) {
+ result.append(MatrixHelper.format(sem, -LENGTH, null));
+ result.append(",");
+ }
+
+ for (int y = 0; y < getDim(1); y++) {
+ result.append("\n");
+ Object sem = getSemantic(1).get(y);
+ result.append(MatrixHelper.format(sem, LENGTH, null));
+ result.append(" ");
+ for (int x = 0; x < getDim(0); x++) {
+ pos[0] = x;
+ pos[1] = y;
+ Object v = getValueIndex(pos);
+ result.append(MatrixHelper.format(v, -LENGTH, null) + ",");
+ }
+ }
+ result.append("\n]");
+ } else {
+ result.append(toStringGeneric());
+ }
+ return result.toString();
+ }
+
+ /**
+ * Representation string de la matrice quelque soit le nombre de dimension
+ * @return
+ */
+ public String toStringGeneric() {
+ StringBuilder result = new StringBuilder();
+ result.append(MatrixHelper.format(getName(), 0, "#NoNameMat"));
+ result.append("(matrix" + getDimCount() + "D)[\n");
+ result.append("dimensions = [");
+ for (int i = 0; i < getDim().length; i++) {
+ result.append(getDim()[i] + ",");
+ }
+ result.append("]\ndata = [");
+ for (MatrixMapIterator i = this.iterator(); i.hasNext();) {
+ result.append(i.next() + ",");
+ }
+ result.append("]\n");
+ return result.toString();
+ }
+
+ public boolean isValidCoordinates(int[] dim) {
+ boolean result = getDimCount() == dim.length;
+ for (int i = 0; result && i < dim.length; i++) {
+ result = 0 <= dim[i] && dim[i] < getDim(i);
+ }
+ return result;
+ }
+
+ public boolean isValidCoordinates(Object[] semantics) {
+ boolean result = getDimCount() == semantics.length;
+ for (int i = 0; result && i < semantics.length; i++) {
+ List semantic = getSemantic(i);
+ result = semantic.contains(semantics[i]);
+ }
+ return result;
+ }
+
+ /**
+ * Copie une matrice dans la matrice actuelle. La matrice à copier à le même
+ * nombre de dimension. Si la matrice à copier est trop grande seul les
+ * éléments pouvant être copier le seront.
+ *
+ * @param mat la matrice à copier
+ * @return return la matrice courante.
+ */
+ public MatrixMap pasteIndex(MatrixMap<E> mat) {
+ return paste(new int[getDimCount()], mat);
+ }
+
+ protected MatrixMap<E> paste(int[] origin, MatrixMap<E> mat) {
+ if (mat != null) {
+ for (MatrixMapIterator<E> mi = mat.iterator(); mi.hasNext();) {
+ E value = mi.next();
+ int[] coordinates = ArrayUtil.sum(origin, mi.getCoordinates());
+ if (isValidCoordinates(coordinates)) {
+ setValueIndex(value, coordinates);
+ }
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Modifie la matrice actuel en metant les valeurs de mat passé en parametre
+ * La copie se fait en fonction de la semantique, si un element dans une
+ * dimension n'est pas trouvé, alors il est passé
+ */
+ public MatrixMap<E> paste(MatrixMap<E> mat) {
+ if (mat != null) {
+ for (MatrixMapIterator<E> mi = mat.iterator(); mi.hasNext();) {
+ E value = mi.next();
+ Object[] sems = mi.getSemanticsCoordinates();
+ if (isValidCoordinates(sems)) {
+ setValue(value, sems);
+ }
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Permet de prendre une sous matrice dans la matrice courante. La sous
+ * matrice a le même nombre de dimensions mais sur une des dimensions on ne
+ * prend que certain élément.
+ *
+ * @param dim la dimension dans lequel on veut une sous matrice si dim est
+ * négatif alors la dimension est prise à partir de la fin par
+ * exemple si l'on veut la derniere dimension il faut passer -1
+ * pour dim
+ * @param start la position dans dim d'ou il faut partir pour prendre la
+ * sous matrice.
+ * @param nb le nombre d'élément à prendre dans la dimension. si nb est
+ * inférieur ou égal à 0 alors cela indique qu'il faut prendre
+ * tous les éléments jusqu'à la fin de la dimension.
+ * @return new matrix
+ */
+ public MatrixMap<E> getSubMatrix(int dim, int start, int nb) {
+ if (dim < 0) {
+ dim = getDimCount() + dim;
+ }
+ if (start < 0) {
+ start = getDim(dim) + start;
+ }
+ if (nb <= 0) {
+ nb = getDim(dim) - start;
+ }
+ return new SubMatrix<E>(this, dim, start, nb);
+ }
+
+ /**
+ * Permet de prendre une sous matrice dans la matrice courante. La sous
+ * matrice a le même nombre de dimensions mais sur une des dimensions on ne
+ * prend que certain élément.
+ *
+ * @param dim la dimension dans lequel on veut une sous matrice
+ * @param start la position dans dim d'ou il faut partir pour prendre la
+ * sous matrice. 0 <= start < dim.size si start est négatif alors
+ * la position de départ est calculé par rapport à la fin de la
+ * dimension, pour avoir le dernier élément il faut passer -1
+ * @param nb le nombre d'élément à prendre dans la dimension si nb est
+ * inférieur ou égal à 0 alors cela indique qu'il faut prendre
+ * tous les éléments jusqu'à la fin de la dimension.
+ * @return new matrix
+ */
+ public MatrixMap<E> getSubMatrix(int dim, Object start, int nb) {
+ int begin = MatrixHelper.indexOf(getSemantics(), dim, start);
+ return getSubMatrix(dim, begin, nb);
+ }
+
+ /**
+ * Add to desambiguas some call with xpath engine, but do the same thing
+ * {@link #getSubMatrix(int, Object[])}
+ *
+ * @param dim
+ * @param elem
+ * @return new matrix
+ */
+ public MatrixMap<E> getSubMatrixOnSemantic(int dim, Object... elem) {
+ MatrixMap<E> result = getSubMatrix(dim, elem);
+ return result;
+ }
+
+ /**
+ * Permet de prendre une sous matrice dans la matrice courante. La sous
+ * matrice a le même nombre de dimensions mais sur une des dimensions on ne
+ * prend que certain élément.
+ *
+ * @param dim la dimension dans lequel on veut une sous matrice
+ * @param elem les éléments dans la dimension à conserver
+ * @return new matrix
+ */
+ public MatrixMap<E> getSubMatrix(int dim, Object... elem) {
+ int[] ielem = new int[elem.length];
+ for (int i = 0; i < ielem.length; i++) {
+ ielem[i] = MatrixHelper.indexOf(getSemantics(), dim, elem[i]);
+ }
+ return getSubMatrix(dim, ielem);
+ }
+
+ /**
+ * Permet de prendre une sous matrice dans la matrice courante.
+ *
+ * Réalise plusieurs appels à {@link #getSubMatrix(int, Object...)} suivant
+ * l'implémentation.
+ *
+ * @param elem les éléments dans la dimension à conserver
+ * @return new matrix
+ */
+ public MatrixMap<E> getSubMatrix(Object[]... elems) {
+
+ // la reduction doit se faire sur le meme nombre de dimension
+ if (elems.length != dim.length) {
+ throw new IllegalArgumentException(String.format(
+ "Can't get sub matrix with different dimension count "
+ + "(expected: %d, got %d)", dim.length, elems.length));
+ }
+
+ MatrixMap<E> result = this;
+ for (int i = 0; i < elems.length; ++i) {
+ if (elems[i] != null) {
+ result = result.getSubMatrix(i, elems[i]);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Permet de prendre une sous matrice dans la matrice courante. La sous
+ * matrice a le même nombre de dimensions mais sur une des dimensions on ne
+ * prend que certain élément.
+ *
+ * @param dim la dimension dans lequel on veut une sous matrice
+ * @param elem les indices des éléments dans la dimension à conserver
+ * @return new matrix
+ */
+ public MatrixMap<E> getSubMatrix(int dim, int[] elem) {
+ return new SubMatrix<E>(this, dim, elem);
+ }
+
+ /**
+ * Permet de prendre une sous matrice dans la matrice courante.
+ *
+ * Réalise plusieurs appels a {@link #getSubMatrix(int, int[])} suivant
+ * l'implementation.
+ *
+ * @param elems les indices des éléments pour chaque dimension à conserver
+ * @return new matrix
+ */
+ public MatrixMap<E> getSubMatrix(int[]... elems) {
+
+ // la reduction doit se faire sur le meme nombre de dimension
+ if (elems.length != dim.length) {
+ throw new IllegalArgumentException(String.format(
+ "Can't get sub matrix with different dimension count "
+ + "(expected: %d, got %d)", dim.length, elems.length));
+ }
+
+ MatrixMap<E> result = this;
+ for (int i = 0; i < elems.length; ++i) {
+ if (elems[i] != null) {
+ result = new SubMatrix<E>(result, i, elems[i]);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Reduit la matrice de sorte que toutes les dimensions qui n'ont qu'un
+ * élement soit supprimée. Au pire cette méthode retourne une matrice à une
+ * seule dimension à un seul élément.
+ *
+ * @return une nouvelle matrice plus petite que la matrice actuelle ou egal
+ * s'il n'y a aucune dimension à supprimer
+ */
+ public MatrixMap<E> reduce() {
+ return reduce(1);
+ }
+
+ /**
+ * Reduit le matrice seulement sur les dimensions passées en argument. Si
+ * une des dimensions passées en arguement n'a pas qu'un seul élément, cette
+ * dimension n'est pas prise en compte.
+ *
+ * @param dims les dimensions sur lequel il faut faire la reduction
+ * @return une nouvelle matrice
+ */
+ public MatrixMap<E> reduceDims(int... dims) {
+ Arrays.sort(dims);
+ // tableau permettant de faire la correspondance entre les dimensions
+ // de la matrice actuelle et les dimentsions de la nouvelle matrice
+ // l'element i du tableau qui correcpond à la dimensions i de la
+ // nouvelle matrice contient la dimension equivalente dans
+ // la matrice actuelle
+ int[] correspondance = new int[getDimCount()];
+ // les nouvelles semantiques
+ List<List> sem = new ArrayList<List>();
+ // les nouveaux noms de dimensions
+ List<String> dimName = new ArrayList<String>();
+ // il faut au moins une dimension pour la matrice
+ int minNbDim = 1;
+ for (int j = getDimCount() - 1; j >= 0; j--) {
+ // si la dimension à plus d'un élément ou qu'il n'est pas dans dims
+ // on garde la dimension
+ if (getDim(j) > 1 || Arrays.binarySearch(dims, j) < 0
+ || j < minNbDim) {
+ // on ne conserve que les dimensions supérieure à 1
+ correspondance[sem.size()] = j;
+ sem.add(getSemantic(j));
+ dimName.add(getDimensionName(j));
+ minNbDim--;
+ }
+ }
+ MatrixMap<E> result = reduce(dimName, sem, correspondance);
+ return result;
+ }
+
+ /**
+ * Reduit la matrice de sorte que toutes les dimensions qui n'ont qu'un
+ * élement soit supprimée. Au pire cette méthode retourne une matrice à une
+ * seule dimension à un seul élément.
+ *
+ * @param minNbDim le nombre minimum de dimension que l'on souhaite pour la
+ * matrice résultat
+ * @return une nouvelle matrice plus petite que la matrice actuelle ou egal
+ * s'il n'y a aucune dimension à supprimer
+ */
+ public MatrixMap<E> reduce(int minNbDim) {
+ // tableau permettant de faire la correspondance entre les dimensions
+ // de la matrice actuelle et les dimentsions de la nouvelle matrice
+ // l'element i du tableau qui correcpond à la dimensions i de la
+ // nouvelle matrice contient la dimension equivalente dans
+ // la matrice actuelle
+ int[] correspondance = new int[getDimCount()];
+ // les nouvelles semantiques
+ List<List> sem = new ArrayList<List>();
+ // les nouveaux noms de dimensions
+ List<String> dimName = new ArrayList<String>();
+ for (int j = getDimCount() - 1; j >= 0; j--) {
+ // si la dimension à plus d'un élément ou si on a pas assez de
+ // dimension pour avoir le minimum demandé on prend la dimension
+ if (getDim(j) > 1 || j < minNbDim) {
+ // on ne conserve que les dimensions supérieure à 1
+ correspondance[sem.size()] = j;
+ sem.add(getSemantic(j));
+ dimName.add(getDimensionName(j));
+ // on vient de prendre une dimension il nous en faut une de
+ // moins
+ minNbDim--;
+ }
+ }
+
+ MatrixMap<E> result = reduce(dimName, sem, correspondance);
+ return result;
+ }
+
+ /**
+ * Create new matrice from the current matrix.
+ *
+ * @param dimName dimension name for new matrix
+ * @param sem semantic for new matrix
+ * @param correspondance array to do the link between current matrix and
+ * returned matrix
+ * @return new matrix
+ */
+ protected MatrixMap<E> reduce(List<String> dimName, List<List> sem, int[] correspondance) {
+ // on converti les listes en tableau en inversant l'ordre car on
+ // a fait un parcours en sens inverse
+ int nbDim = sem.size();
+ List[] newSemantics = new List[nbDim];
+ String[] newDimNames = new String[nbDim];
+ int[] tmpcorrespondance = new int[nbDim];
+ for (int i = 0; i < nbDim; i++) {
+ newSemantics[i] = sem.get(nbDim - 1 - i);
+ newDimNames[i] = dimName.get(nbDim - 1 - i);
+ tmpcorrespondance[i] = correspondance[nbDim - 1 - i];
+ }
+ correspondance = tmpcorrespondance;
+
+ MatrixMap<E> result = new MatrixMapFixed<E>(getName(), newDimNames, newSemantics);
+
+ // on reprend les valeurs
+ int[] newCoordinates = new int[result.getDimCount()];
+ for (MatrixMapIterator<E> mi = iterator(); mi.hasNext();) {
+ E value = mi.next();
+ int[] oldCoordinates = mi.getCoordinates();
+ for (int i = 0; i < newCoordinates.length; i++) {
+ newCoordinates[i] = oldCoordinates[correspondance[i]];
+ }
+ result.setValueIndex(value, newCoordinates);
+ }
+ return result;
+ }
+
+ public MatrixMap<E> extend(Object... sems) {
+ String name = getName();
+ String[] dimNames = getDimensionNames();
+ SemanticList[] semantics = getSemantics();
+
+ // si pas assez de dimension on en rajoute
+ if (sems.length > semantics.length) {
+ String[] newDimNames = new String[sems.length];
+ System.arraycopy(dimNames, 0, newDimNames, 0, dimNames.length);
+ dimNames = newDimNames;
+
+ SemanticList[] newSems = new SemanticList[sems.length];
+ System.arraycopy(semantics, 0, newSems, 0, semantics.length);
+ semantics = newSems;
+
+ for (int i = semantics.length; i < newSems.length; i++) {
+ newSems[i] = new SemanticList();
+ }
+ }
+
+ // si les objets demande n'existe pas dans la semantics on l'ajoute
+ for (int i = 0; i<sems.length; i++) {
+ if (semantics[i].indexOf(sems[i]) == -1) {
+ semantics[i].add(sems[i]);
+ }
+ }
+
+ MatrixMap<E> result = MatrixMap.Factory.create(name, dimNames, semantics);
+ result.paste(this);
+ return result;
+ }
+
+ }
+
+ /**
+ * Pour l'instant une sous matrice a obligatoirement le meme nombre de dimension
+ * que la matrice qu'elle contient. Elle permet juste de reduire le nombre
+ * d'element d'une dimension.
+ *
+ * C'est comme une "vue" réduite sur la vraie matrices.
+ */
+ static public class SubMatrix<E> extends AbstractMatrixMap<E> { // SubMatrix
+
+ protected MatrixMap<E> matrix = null;
+ protected DimensionConverter converter = null;
+
+ public SubMatrix(MatrixMap<E> matrix, int dim, int start, int nb) {
+ super(matrix.getName(), matrix.getDimensionNames(), matrix.getSemantics());
+ this.matrix = matrix;
+
+ converter = new ShiftConverter(dim, start, nb);
+ setSemantic(dim, getSemantic(dim).subList(start, start + nb));
+ getDim()[dim] = nb;
+ }
+
+ public SubMatrix(MatrixMap<E> matrix, int dim, int[] elem) {
+ super(matrix.getName(), matrix.getDimensionNames(), matrix.getSemantics());
+ this.matrix = matrix;
+
+ converter = new MappingConverter(dim, elem);
+
+ List oldSemantic = getSemantic(dim);
+ List newSemantic = new LinkedList();
+ for (int i = 0; i < elem.length; i++) {
+ newSemantic.add(oldSemantic.get(elem[i]));
+ }
+ setSemantic(dim, newSemantic);
+ getDim()[dim] = elem.length;
+ }
+
+ @Override
+ public MatrixMapIterator<E> iterator() {
+ return new SubMatrixIterator<E>(this);
+ }
+
+ @Override
+ public E getValueIndex(int ... coordinates) {
+ return matrix.getValueIndex(converter.convertCoordinates(coordinates));
+ }
+
+ @Override
+ public void setValueIndex(E value, int ... coordinates) {
+ matrix.setValueIndex(value, converter.convertCoordinates(coordinates));
+ }
+
+ protected class SubMatrixIterator<E> implements MatrixMapIterator<E> {
+
+ protected SubMatrix<E> subMatrix = null;
+ protected int[] cpt = null;
+ protected int[] last = null;
+
+ public SubMatrixIterator(SubMatrix<E> subMatrix) {
+ this.subMatrix = subMatrix;
+ cpt = new int[subMatrix.getDimCount()];
+ cpt[cpt.length - 1] = -1;
+
+ last = new int[subMatrix.getDimCount()];
+ for (int i = 0; i < last.length; i++) {
+ last[i] = subMatrix.getDim(i) - 1;
+ }
+
+ }
+
+ @Override
+ public boolean hasNext() {
+ return !Arrays.equals(cpt, last);
+ }
+
+ @Override
+ public E next() {
+ int ret = 1;
+ int[] dim = getDim();
+ for (int i = cpt.length - 1; i >= 0; i--) {
+ cpt[i] = cpt[i] + ret;
+ ret = cpt[i] / dim[i];
+ cpt[i] = cpt[i] % dim[i];
+ }
+ E result = getValue();
+ return result;
+ }
+
+ @Override
+ public void remove() {
+ setValue(null);
+ }
+
+ public int[] getCoordinates() {
+ return cpt;
+ }
+
+ public Object[] getSemanticsCoordinates() {
+ int[] coordinates = getCoordinates();
+ Object[] result = MatrixHelper.dimensionToSemantics(subMatrix.getSemantics(), coordinates);
+ return result;
+ }
+
+ public E getValue() {
+ return subMatrix.getValueIndex(getCoordinates());
+ }
+
+ public void setValue(E value) {
+ subMatrix.setValue(value, getCoordinates());
+ }
+ }
+
+ /**
+ * Permet de faire une conversion de la dimension demandé dans la sous
+ * matrice avec la position reel de la matrice sous jacente.
+ */
+ protected interface DimensionConverter extends Serializable {
+ public int[] convertCoordinates(int[] coordinates);
+ }
+
+ /**
+ * La conversion est juste un decalage d'indice
+ */
+ protected static class ShiftConverter implements DimensionConverter {
+
+ /** serialVersionUID. */
+ private static final long serialVersionUID = 1L;
+
+ protected int dim;
+ protected int start;
+ protected int nb;
+
+ public ShiftConverter(int dim, int start, int nb) {
+ this.dim = dim;
+ this.start = start;
+ this.nb = nb;
+ }
+
+ @Override
+ public int[] convertCoordinates(int[] coordinates) {
+ int[] result = null;
+ if (coordinates[dim] < nb) {
+ result = new int[coordinates.length];
+ System.arraycopy(coordinates, 0, result, 0, result.length);
+ result[dim] = result[dim] + start;
+ } else {
+ throw new NoSuchElementException(
+ "L'indice est supérieur au nombre d'élement de la sous matrice pour cette dimension.");
+ }
+ return result;
+ }
+ }
+
+ /**
+ * La conversion est le mapping d'un element vers un autre element.
+ */
+ protected static class MappingConverter implements DimensionConverter {
+
+ /** serialVersionUID. */
+ private static final long serialVersionUID = -6367416559713556559L;
+ protected int dim;
+ protected int[] elem = null;
+
+ public MappingConverter(int dim, int[] elem) {
+ this.dim = dim;
+ this.elem = new int[elem.length];
+ System.arraycopy(elem, 0, this.elem, 0, elem.length);
+ }
+
+ @Override
+ public int[] convertCoordinates(int[] coordinates) {
+ int[] result = null;
+ if (coordinates[dim] < elem.length) {
+ result = new int[coordinates.length];
+ System.arraycopy(coordinates, 0, result, 0, result.length);
+ result[dim] = elem[coordinates[dim]];
+
+ } else {
+ throw new NoSuchElementException(
+ "L'indice est supérieur au nombre d'élements de la sous matrice pour cette dimension.");
+ }
+ return result;
+ }
+ }
+ } // SubMatrix
+
+ /**
+ * Objet matrice qui ne permet que le stockage avec des positions int
+ * dans une matrice a autant de dimension que l'on souhaite.
+ */
+ static public class Matrix<E> implements Iterable<E> { // BasicMatrix
+
+ /** Les dimensions de la matrice */
+ protected int[] dimensions = null;
+ /** La matrice en représentation linéaire */
+ protected Vector<E> data = null;
+
+ /**
+ * tableau de facteur permettant de convertir les coordonnées dans la
+ * matrice en un indice dans la représentation linéaire de la matrice
+ */
+ protected int[] linearFactor = null;
+
+ /**
+ * Crée une nouvelle matrice ayant les dimensions demandées.
+ *
+ * @param factory factory
+ * @param dimensions dimensions
+ */
+ public Matrix(int[] dimensions) {
+ checkDim(dimensions);
+
+ // copie des dimensions pour que personne à l'extérieur de l'objet
+ // ne puisse les modifiers par la suite
+ this.dimensions = new int[dimensions.length];
+ System.arraycopy(dimensions, 0, this.dimensions, 0, dimensions.length);
+
+ // calcul du linearFactor
+ linearFactor = new int[dimensions.length];
+ linearFactor[linearFactor.length - 1] = 1;
+ for (int i = linearFactor.length - 2; i >= 0; i--) {
+ linearFactor[i] = linearFactor[i + 1] * dimensions[i + 1];
+ }
+
+ // creation de la matrice lineaire
+ data = new Vector<E>(linearFactor[0] * dimensions[0]);
+ }
+
+ /**
+ * Retourne le nombre de dimension de la matrice
+ *
+ * @return le nombre de dimension de la matrice;
+ */
+ public int getNbDim() {
+ return dimensions.length;
+ }
+
+ /**
+ * Retourne la taille d'une dimension
+ *
+ * @param dim la dimension dont on souhaite la taille
+ * @return la taille d'une dimension
+ */
+ public int getDim(int dim) {
+ checkDim(dim);
+ return dimensions[dim];
+ }
+
+ /**
+ * Retourne un tableau representant les dimensions de la matrice. Le tableau
+ * retourné n'est pas une copie, il ne faut donc pas le modifier
+ *
+ * @return le tableau des dimensions.
+ */
+ public int[] getDim() {
+ return dimensions;
+ }
+
+ /**
+ * Retourne un element de la matrice
+ *
+ * @param pos la position de l'element à retourner
+ * @return un element de la matrice
+ */
+ public E getValue(int[] pos) {
+ int indice = coordonatesToLinear(pos);
+ return data.getValue(indice);
+ }
+
+ /**
+ * Modifie un élement de la matrice
+ *
+ * @param pos la position de l'element à modifier
+ * @param value la nouvelle valeur à mettre dans la matrice
+ */
+ public void setValue(int[] pos, E value) {
+ int indice = coordonatesToLinear(pos);
+ data.setValue(indice, value);
+ }
+
+ /**
+ * Retourne un objet Inc pret a etre utilisé pour boucler sur tous les
+ * element de la matrice.
+ *
+ * @return un objet Inc pret à être utilisé
+ */
+ public MatrixIterator<E> iterator() {
+ return new MatrixIterator<E>(this);
+ }
+
+ /**
+ * Permet de faire un traitement sur chaque valeur de la matrice
+ *
+ * @param f la fonction a appliquer à chaque élement de la matrice
+ */
+ public void map(MapFunction f) {
+ data.map(f);
+ }
+
+ /**
+ * Permet de convertir les coordonnées d'un élément en un indice dans la
+ * représentation linéraire de la matrice.
+ *
+ * @param coordonates les coordonnées à lineariser
+ * @return un indice réprésentant les coordonnées de façon linéaire
+ */
+ protected int coordonatesToLinear(int[] coordonates) {
+ checkPos(coordonates);
+
+ int result = 0;
+ for (int i = 0; i < linearFactor.length; i++) {
+ result += coordonates[i] * linearFactor[i];
+ }
+ return result;
+ }
+
+ /**
+ * Convertie une coordonnée lineaire en coordonnées spaciales
+ *
+ * @param pos la coordonnée linéaire
+ * @return les coordonnées spaciales de l'élément
+ */
+ protected int[] linearToCoordinates(int pos) {
+ int[] result = new int[linearFactor.length];
+
+ for (int i = 0; i < result.length; i++) {
+ result[i] = pos / linearFactor[i];
+ pos -= result[i] * linearFactor[i];
+ }
+ return result;
+ }
+
+ /**
+ * Permet de vérifier que les dimensions de la nouvelle matrice sont
+ * corrects
+ *
+ * @param dim les dimensions de la nouvelle matrice
+ * @throws IllegalArgumentException si une dimension n'est pas valide
+ */
+ protected void checkDim(int[] dim) {
+ for (int i = 0; i < dim.length; i++) {
+ if (dim[i] <= 0) {
+ throw new IllegalArgumentException(String.format(
+ "Dimension %s is invalid %s", i, dim[i]));
+ }
+ }
+ }
+
+ /**
+ * Permet de vérifier qu'une dimension demandé existe bien dans la matrice
+ *
+ * @param dim la position de la dimension que l'on souhaite
+ * @throws IndexOutOfBoundsException si la dimension demandée n'existe pas
+ */
+ protected void checkDim(int dim) {
+ if (dim < 0 || dim >= getNbDim()) {
+ throw new IndexOutOfBoundsException(String.format(
+ "Invalid dimension %s max dimension is %s",
+ dim, getNbDim()));
+ }
+ }
+
+ /**
+ * Verifie que les coordonnées demandé appartiennent bien à la matrice
+ *
+ * @param pos les coordonnées souhaitées dans la matrice
+ * @throws NoSuchElementException si les coordonnées ne correspondent pas à
+ * un élement de la matrice
+ */
+ protected void checkPos(int[] pos) {
+ int[] dim = getDim();
+ boolean result = dim.length == pos.length;
+ for (int i = 0; result && i < dim.length; i++) {
+ result = (0 <= pos[i]) && (pos[i] < dim[i]);
+ }
+ if (!result) {
+ throw new NoSuchElementException(String.format(
+ "Invalid element asked %s for real dimension %s", Arrays.toString(pos), Arrays
+ .toString(dim)));
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer result = new StringBuffer();
+ if (getNbDim() == 1) {
+ result.append("matrix1D [");
+ for (int i = 0; i < data.size(); i++) {
+ result.append(data.getValue(i) + ",");
+ }
+ result.append("]");
+ } else if (getNbDim() == 2) {
+ int[] pos = new int[2];
+ result.append("matrix2D [");
+ for (int y = 0; y < getDim(1); y++) {
+ result.append("\n");
+ for (int x = 0; x < getDim(0); x++) {
+ pos[0] = x;
+ pos[1] = y;
+ result.append(getValue(pos) + ",");
+ }
+ }
+ result.append("]");
+ } else {
+ result.append("dimensions = [\n");
+ for (int i = 0; i < dimensions.length; i++) {
+ result.append(dimensions[i] + ",");
+ }
+ result.append("\n]\nmatrice = [\n");
+ for (int i = 0; i < data.size(); i++) {
+ result.append(data.getValue(i) + ",");
+ }
+ result.append("\n]\nlinearFactor = [\n");
+ for (int i = 0; i < linearFactor.length; i++) {
+ result.append(linearFactor[i] + ",");
+ }
+ result.append("\n]\n");
+ }
+ return result.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof Matrix) {
+ Matrix other = (Matrix) o;
+ return this == o
+ || (Arrays.equals(this.dimensions, other.dimensions) && this.data
+ .equals(other.data));
+ }
+ return false;
+ }
+
+ } // BasicMatrix
+
+ static public class MatrixIterator<E> implements Iterator<E> { // MatrixIteratorImpl
+
+ protected Matrix<E> matrix = null;
+ protected int pos = -1;
+
+ /**
+ * @param matrix la matrice sur lequel l'iterator doit travailler
+ */
+ public MatrixIterator(Matrix<E> matrix) {
+ this.matrix = matrix;
+ pos = -1;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return pos + 1 < matrix.data.size();
+ }
+
+ @Override
+ public E next() {
+ if (hasNext()) {
+ pos++;
+ } else {
+ throw new NoSuchElementException();
+ }
+ E result = getValue();
+ return result;
+ }
+
+ @Override
+ public void remove() {
+ setValue(null);
+ }
+
+ public E getValue() {
+ return matrix.data.getValue(pos);
+ }
+
+ public void setValue(E value) {
+ matrix.data.setValue(pos, value);
+ }
+
+ public int[] getCoordinates() {
+ return matrix.linearToCoordinates(pos);
+ }
+
+ } // MatrixIteratorImpl
+
+ /**
+ * Permet de stocker des données à une position lineaire et de la redemander.
+ * Cette classe ne gére que les données lineaire. L'avantage de cette classe est
+ * de ne conserver que les elements differents de la valeur par defaut, ce qui
+ * minimize la taille du tableau necessaire a conserver les données.
+ *
+ */
+ static public class Vector<E> { // Vector
+
+ /** maximum number of element, maximum pos value */
+ protected int capacity = 0;
+
+ /** la valeur par defaut */
+ protected E defaultValue = null;
+
+ /** contient la position de l'element, le tableau est trie */
+ protected int[] position;
+ protected int positionSize = 0;
+
+ /** contient la valeur de l'element */
+ protected ArrayList<E> data = new ArrayList<E>();
+
+ public Vector(int capacity) {
+ this.capacity = capacity;
+ position = new int[8];
+ Arrays.fill(position, Integer.MAX_VALUE);
+ }
+
+ public Vector(int capacity, E defaultValue) {
+ this(capacity);
+ this.defaultValue = defaultValue;
+ }
+
+ public int size() {
+ return capacity;
+ }
+
+ // poussin 20060827 TODO: verifier l'implantation, il semble quelle soit
+ // fausse et ne puisse pas recherche le nombre max correctement
+ public E getMaxOccurrence() {
+ E result = defaultValue;
+
+ E[] tmp = (E[])data.toArray();
+
+ // si potentiellement il y a plus d'element identique dans data
+ // que de valeur par defaut, on recherche la valeur possible
+ if (this.capacity < 2 * tmp.length) {
+ Arrays.sort(tmp);
+
+ // le nombre de fois que l'on a rencontrer la valeur la plus
+ // nombreuse
+ int max = 1;
+ // le nombre de fois que l'on a rencontrer la valeur courante
+ int count = 1;
+ // la valeur la plus rencontrer
+ result = tmp[0];
+ // la valeur que l'on vient de traiter précédement
+ E old = tmp[0];
+ // la valeur courante lu dans le tableaux
+ E current = tmp[0];
+ // tant que l'on peut encore trouve un element plus nombreux dans le
+ // tableau on le parcours
+ for (int i = 1; max < tmp.length - i + count && i < tmp.length; i++) {
+ current = tmp[i];
+
+ if (current == old) {
+ count++;
+ } else {
+ if (count > max) {
+ max = count;
+ result = old;
+ }
+ count = 1;
+ old = current;
+ }
+ }
+ if (count > max) {
+ max = count;
+ result = current;
+ }
+
+ if (max <= capacity - tmp.length) {
+ // en fin de compte, il n'y a pas plus d'element identique
+ // dans data que de defaultValue
+ result = defaultValue;
+ }
+ }
+
+ return result;
+ }
+
+ protected void checkPos(int pos) {
+ if (pos < 0 || pos >= capacity) {
+ throw new IllegalArgumentException("pos " + pos + " is not in [0, "
+ + capacity + "]");
+ }
+ }
+
+ public E getValue(int pos) {
+ checkPos(pos);
+
+ E result = defaultValue;
+ int index = findIndex(pos);
+ if (index >= 0) {
+ result = data.get(index);
+ }
+ return result;
+ }
+
+ public void setValue(int pos, E value) {
+ checkPos(pos);
+
+ int index = findIndex(pos);
+ if (index >= 0) {
+ if (value == defaultValue) {
+ // il etait present, on supprime l'element
+ removeElementAt(index);
+ data.remove(index);
+ } else {
+ // il etait deja present, on modifie la valeur
+ data.set(index, value);
+ }
+ } else {
+ // il n'etait pas present
+ if (value != defaultValue) {
+ // il faut ajouter dans position et dans data
+ index = -index - 1;
+
+ addElementAt(index, pos);
+ data.add(index, value);
+ }
+ }
+ }
+
+ public boolean equals(Object o) {
+ boolean result = false;
+ if (o instanceof Vector) {
+ Vector other = (Vector) o;
+ result = Arrays.equals(this.position, other.position)
+ && data.equals(other.data);
+ }
+ return result;
+ }
+
+ /**
+ * retourne la position dans le tableau position de la position lineaire
+ *
+ * @param pos
+ * @return la position ou < 0 donnant la position de l'element s'il etait
+ * present
+ */
+ protected int findIndex(int pos) {
+ return Arrays.binarySearch(position, pos);
+ }
+
+ protected void ensureCapacity(int mincap) {
+ if (mincap > position.length) {
+ int newcap = (position.length * 3) / 2 + 1;
+ int olddata[] = position;
+ position = new int[newcap >= mincap ? newcap : mincap];
+ System.arraycopy(olddata, 0, position, 0, positionSize);
+ for (int i = positionSize; i < position.length; i++) {
+ position[i] = Integer.MAX_VALUE;
+ }
+ }
+ }
+
+ protected void addElementAt(int index, int element) {
+ ensureCapacity(positionSize + 1);
+ int numtomove = positionSize - index;
+ System.arraycopy(position, index, position, index + 1, numtomove);
+ position[index] = element;
+ positionSize++;
+ }
+
+ protected int removeElementAt(int index) {
+ int oldval = position[index];
+ int numtomove = positionSize - index - 1;
+ if (numtomove > 0) {
+ System.arraycopy(position, index + 1, position, index, numtomove);
+ }
+ positionSize--;
+ position[positionSize] = Integer.MAX_VALUE;
+ return oldval;
+ }
+
+ /**
+ * On recopie tous les attributs pour que le vector ressemble exactement a
+ * celui passé en argument
+ */
+ public void paste(Vector<E> v) {
+ this.capacity = v.capacity;
+ this.defaultValue = v.defaultValue;
+ this.positionSize = v.positionSize;
+ this.position = new int[v.position.length];
+ System.arraycopy(v.position, 0, this.position, 0,
+ this.position.length);
+ this.data.clear();
+ this.data.addAll(v.data);
+ }
+
+ /**
+ * on applique sur chaque donnée existante et sur default
+ */
+ public void map(MapFunction<E> f) {
+ // on commence toujours par modifier la valeur par defaut
+ // car les valeurs suivante pourrait prendre cette valeur
+ // et donc disparaitre des tableaux si besoin
+ defaultValue = f.apply(defaultValue);
+ // on fait la boucle a l'envers au cas ou on supprime des valeurs
+ for (int i = data.size() - 1; i >= 0; i--) {
+ E value = f.apply(data.get(i));
+ if (value == defaultValue) {
+ // il etait present, on supprime l'element
+ removeElementAt(i);
+ data.remove(i);
+ } else {
+ // il etait deja present, on modifie la valeur
+ data.set(i, value);
+ }
+ }
+ }
+ } // Vector
+
+ /**
+ * Permet de faire un traitement sur des valeurs et d'en retourner
+ * des nouvelles.
+ */
+ static public interface MapFunction<E> { // MapFunction
+
+ /**
+ * Permet de faire un traitement sur value et de retourne une nouvelle
+ * valeur.
+ *
+ * @param value la valeur courante sur lequel il faut faire le traitement
+ * @return la nouvelle valeur à mettre dans la matrice à la place de
+ * l'ancienne.
+ */
+ E apply(E value);
+
+ } // MapFunction
+
+}
Added: trunk/nuiton-utils/src/test/java/org/nuiton/util/MatrixMapTest.java
===================================================================
--- trunk/nuiton-utils/src/test/java/org/nuiton/util/MatrixMapTest.java (rev 0)
+++ trunk/nuiton-utils/src/test/java/org/nuiton/util/MatrixMapTest.java 2011-06-21 11:00:42 UTC (rev 2151)
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2011 poussin. All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.nuiton.util;
+
+import java.util.Arrays;
+import java.util.List;
+import org.junit.Assert;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author poussin
+ */
+public class MatrixMapTest {
+
+ @Test
+ public void testSubMatrix() {
+ List<String> sem1 = Arrays.asList("xA", "xB", "xC", "xD");
+ List<String> sem2 = Arrays.asList("ya", "yb", "yc", "yd", "ye");
+ MatrixMap<String> m = MatrixMap.Factory.create(new List[]{sem1, sem2});
+
+ m.setValue("a1", "xA", "ya");
+ m.setValue("a2", "xA", "yb");
+ m.setValue("a3", "xA", "yc");
+ m.setValue("a4", "xA", "yd");
+ m.setValue("a5", "xA", "ye");
+
+ m.setValue("b1", "xB", "ya");
+ m.setValue("b2", "xB", "yb");
+ m.setValue("b3", "xB", "yc");
+ m.setValue("b4", "xB", "yd");
+ m.setValue("b5", "xB", "ye");
+
+ m.setValue("c1", "xC", "ya");
+ m.setValue("c2", "xC", "yb");
+ m.setValue("c3", "xC", "yc");
+ m.setValue("c4", "xC", "yd");
+ m.setValue("c5", "xC", "ye");
+
+ m.setValue("d1", "xD", "ya");
+ m.setValue("d2", "xD", "yb");
+ m.setValue("d3", "xD", "yc");
+ m.setValue("d4", "xD", "yd");
+ m.setValue("d5", "xD", "ye");
+
+ System.out.println(m.toString());
+
+ MatrixMap sub = m.getSubMatrix(0, "xA", "xC");
+
+ System.out.println(sub);
+ }
+
+ @Test
+ public void testExtend() {
+ List<String> sem1 = Arrays.asList("xA", "xB", "xC");
+ List<String> sem2 = Arrays.asList("ya", "yb", "yc", "yd", "ye");
+ MatrixMap<String> m = MatrixMap.Factory.createElastic(new List[]{sem1, sem2});
+
+ m.setValue("a1", "xA", "ya");
+ m.setValue("a2", "xA", "yb");
+ m.setValue("a3", "xA", "yc");
+ m.setValue("a4", "xA", "yd");
+ m.setValue("a5", "xA", "ye");
+
+ m.setValue("b1", "xB", "ya");
+ m.setValue("b2", "xB", "yb");
+ m.setValue("b3", "xB", "yc");
+ m.setValue("b4", "xB", "yd");
+ m.setValue("b5", "xB", "ye");
+
+ m.setValue("c1", "xC", "ya");
+ m.setValue("c2", "xC", "yb");
+ m.setValue("c3", "xC", "yc");
+ m.setValue("c4", "xC", "yd");
+ m.setValue("c5", "xC", "ye");
+
+ System.out.println(m.toString());
+
+ m.setValue("d1", "xD", "ya");
+ m.setValue("d2", "xD", "yb");
+ m.setValue("d3", "xD", "yc");
+ m.setValue("d4", "xD", "yd");
+ m.setValue("d5", "xD", "ye");
+
+ System.out.println(m.toString());
+ }
+
+}
1
0
Author: echatellier
Date: 2011-06-16 10:31:43 +0200 (Thu, 16 Jun 2011)
New Revision: 2150
Url: http://nuiton.org/repositories/revision/nuiton-utils/2150
Log:
#1594 Update xwork to 2.2.3
Modified:
trunk/pom.xml
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2011-06-08 14:05:35 UTC (rev 2149)
+++ trunk/pom.xml 2011-06-16 08:31:43 UTC (rev 2150)
@@ -185,7 +185,7 @@
<nuitonI18nVersion>2.4</nuitonI18nVersion>
<aspectwerkzVersion>2.0</aspectwerkzVersion>
- <xworkVersion>2.2.1.1</xworkVersion>
+ <xworkVersion>2.2.3</xworkVersion>
<!-- i18n configuration -->
<i18n.bundles>fr_FR,en_GB,es_ES</i18n.bundles>
1
0
08 Jun '11
Author: echatellier
Date: 2011-06-08 16:05:35 +0200 (Wed, 08 Jun 2011)
New Revision: 2149
Url: http://nuiton.org/repositories/revision/nuiton-utils/2149
Log:
Add comment about grep and sed methods on windows
Modified:
trunk/nuiton-utils/src/main/java/org/nuiton/util/FileUtil.java
Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/FileUtil.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/FileUtil.java 2011-06-07 20:09:12 UTC (rev 2148)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/FileUtil.java 2011-06-08 14:05:35 UTC (rev 2149)
@@ -1181,6 +1181,9 @@
*
* http://java.sun.com/javase/6/docs/technotes/guides/io/example/Grep.java
*
+ * May fail on windows with error :
+ * The requested operation cannot be performed on a file with a user-mapped section open
+ *
* @param searchRegex regex to search into file
* @param f file to search into
* @param encoding encoding to use
@@ -1230,6 +1233,9 @@
/**
* Java implementation for the unix grep command.
*
+ * May fail on windows with error :
+ * The requested operation cannot be performed on a file with a user-mapped section open
+ *
* @param searchRegex regex to search into file
* @param rootDirectory directory to seacrh into
* @param fileRegex regex for file to find in {@code rootDirectory}
@@ -1257,6 +1263,9 @@
/**
* Search for files matching regex in current directory.
*
+ * May fail on windows with error :
+ * The requested operation cannot be performed on a file with a user-mapped section open
+ *
* @param searchRegex regex to search into file
* @param fileRegex regex for file to find in current dir
* @param encoding encoding to use
@@ -1279,6 +1288,9 @@
*
* Oginal source code from http://kickjava.com/src/org/apache/lenya/util/SED.java.htm.
*
+ * May fail on windows with error :
+ * The requested operation cannot be performed on a file with a user-mapped section open
+ *
* @param searchRegex Prefix which shall be replaced
* @param replace Prefix which is going to replace the original
* @param file File which sed shall be applied
@@ -1328,6 +1340,9 @@
/**
* Java implementation for the unix sed command.
*
+ * May fail on windows with error :
+ * The requested operation cannot be performed on a file with a user-mapped section open
+ *
* @param searchRegex regex to search into file
* @param replace string to replace matching patterns
* @param rootDirectory directory to search into
@@ -1350,6 +1365,9 @@
/**
* Java implementation for the unix sed command.
*
+ * May fail on windows with error :
+ * The requested operation cannot be performed on a file with a user-mapped section open
+ *
* @param searchRegex regex to search into file
* @param replace string to replace matching patterns
* @param fileRegex regex for file to find in current dir
1
0
Author: tchemit
Date: 2011-06-07 22:09:12 +0200 (Tue, 07 Jun 2011)
New Revision: 2148
Url: http://nuiton.org/repositories/revision/nuiton-utils/2148
Log:
Update mavenpom4redmineAndCentral to 2.5.5.
Modified:
trunk/pom.xml
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2011-05-26 16:00:41 UTC (rev 2147)
+++ trunk/pom.xml 2011-06-07 20:09:12 UTC (rev 2148)
@@ -33,7 +33,7 @@
<parent>
<groupId>org.nuiton</groupId>
<artifactId>mavenpom4redmineAndCentral</artifactId>
- <version>2.5.4</version>
+ <version>2.5.5</version>
</parent>
<artifactId>nuiton-utils-parent</artifactId>
1
0
26 May '11
Author: echatellier
Date: 2011-05-26 18:00:41 +0200 (Thu, 26 May 2011)
New Revision: 2147
Url: http://nuiton.org/repositories/revision/nuiton-utils/2147
Log:
Add big warning about split method limit (buggy with special chars).
Modified:
trunk/nuiton-utils/src/main/java/org/nuiton/util/StringUtil.java
Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/StringUtil.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/StringUtil.java 2011-05-15 12:18:55 UTC (rev 2146)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/StringUtil.java 2011-05-26 16:00:41 UTC (rev 2147)
@@ -5,7 +5,7 @@
* $Id$
* $HeadURL$
* %%
- * Copyright (C) 2004 - 2010 CodeLutin
+ * Copyright (C) 2004 - 2011 CodeLutin, Chatellier Eric
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -23,17 +23,6 @@
* #L%
*/
-/* *
- * StringUtil.java
- *
- * Created: Sun Apr 14 2002
- *
- * @author POUSSIN Benjamin <bpoussin(a)free.fr>
- * Copyright Code Lutin
- * @version $Revision$
- *
- * Mise a jour: $Date$
- * par : */
package org.nuiton.util;
import java.awt.Color;
@@ -231,6 +220,11 @@
* this method count the number of open char end close char to split
* correctly argument
*
+ * WARNING: cette method ne fonctionne pas si le contenu contient
+ * des carateres utilisé pour le parsing et présent une seule fois.
+ * Par exemple: "l'idenfiant" contient ' qui empeche totalement le
+ * parsing de fonctionner.
+ *
* @param args string to split
* @param separator separator use to split string
* @return array of string
@@ -241,9 +235,14 @@
/**
- * Use to split string array representation in array according with swixat
- * seperator list
- *
+ * Use to split string array representation in array according with ',' as
+ * default separator.
+ *
+ * WARNING: cette method ne fonctionne pas si le contenu contient
+ * des carateres utilisé pour le parsing et présent une seule fois.
+ * Par exemple: "l'idenfiant" contient ' qui empeche totalement le
+ * parsing de fonctionner.
+ *
* @param stringList string that represent array
* @return array with length > 0 if listAsString != null or null
*/
@@ -260,6 +259,11 @@
* this method count the number of open char end close char to split
* correctly argument
*
+ * WARNING: cette method ne fonctionne pas si le contenu contient
+ * des carateres utilisé pour le parsing et présent une seule fois.
+ * Par exemple: "l'idenfiant" contient ' qui empeche totalement le
+ * parsing de fonctionner.
+ *
* @param openingChars list of opening caracteres
* @param closingChars list of closing caracteres
* @param args string to split
1
0
r2146 - in trunk: . nuiton-profiling nuiton-utils nuiton-validator
by hudson@users.nuiton.org 15 May '11
by hudson@users.nuiton.org 15 May '11
15 May '11
Author: hudson
Date: 2011-05-15 14:18:55 +0200 (Sun, 15 May 2011)
New Revision: 2146
Url: http://nuiton.org/repositories/revision/nuiton-utils/2146
Log:
[maven-release-plugin] prepare for next development iteration
Modified:
trunk/nuiton-profiling/pom.xml
trunk/nuiton-utils/pom.xml
trunk/nuiton-validator/pom.xml
trunk/pom.xml
Modified: trunk/nuiton-profiling/pom.xml
===================================================================
--- trunk/nuiton-profiling/pom.xml 2011-05-15 12:18:54 UTC (rev 2145)
+++ trunk/nuiton-profiling/pom.xml 2011-05-15 12:18:55 UTC (rev 2146)
@@ -33,7 +33,7 @@
<parent>
<groupId>org.nuiton</groupId>
<artifactId>nuiton-utils-parent</artifactId>
- <version>2.2</version>
+ <version>2.2.1-SNAPSHOT</version>
</parent>
<artifactId>nuiton-profiling</artifactId>
Modified: trunk/nuiton-utils/pom.xml
===================================================================
--- trunk/nuiton-utils/pom.xml 2011-05-15 12:18:54 UTC (rev 2145)
+++ trunk/nuiton-utils/pom.xml 2011-05-15 12:18:55 UTC (rev 2146)
@@ -33,7 +33,7 @@
<parent>
<groupId>org.nuiton</groupId>
<artifactId>nuiton-utils-parent</artifactId>
- <version>2.2</version>
+ <version>2.2.1-SNAPSHOT</version>
</parent>
<artifactId>nuiton-utils</artifactId>
Modified: trunk/nuiton-validator/pom.xml
===================================================================
--- trunk/nuiton-validator/pom.xml 2011-05-15 12:18:54 UTC (rev 2145)
+++ trunk/nuiton-validator/pom.xml 2011-05-15 12:18:55 UTC (rev 2146)
@@ -33,7 +33,7 @@
<parent>
<groupId>org.nuiton</groupId>
<artifactId>nuiton-utils-parent</artifactId>
- <version>2.2</version>
+ <version>2.2.1-SNAPSHOT</version>
</parent>
<artifactId>nuiton-validator</artifactId>
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2011-05-15 12:18:54 UTC (rev 2145)
+++ trunk/pom.xml 2011-05-15 12:18:55 UTC (rev 2146)
@@ -37,7 +37,7 @@
</parent>
<artifactId>nuiton-utils-parent</artifactId>
- <version>2.2</version>
+ <version>2.2.1-SNAPSHOT</version>
<modules>
<module>nuiton-utils</module>
@@ -220,12 +220,12 @@
<!-- Source control management. -->
<scm>
<connection>
- scm:svn:http://svn.nuiton.org/svn/nuiton-utils/tags/nuiton-utils-2.2
+ scm:svn:http://svn.nuiton.org/svn/nuiton-utils/trunk
</connection>
<developerConnection>
- scm:svn:http://svn.nuiton.org/svn/nuiton-utils/tags/nuiton-utils-2.2
+ scm:svn:http://svn.nuiton.org/svn/nuiton-utils/trunk
</developerConnection>
- <url>http://www.nuiton.org/repositories/browse/nuiton-utils/tags/nuiton-utils-2.2</url>
+ <url>http://www.nuiton.org/repositories/browse/nuiton-utils/trunk</url>
</scm>
</project>
1
0