Revision 47652
Added by Claudio Atzori almost 7 years ago
modules/cnr-misc-utils/tags/cnr-misc-utils-1.0.4/deploy.info | ||
---|---|---|
1 |
{"type_source": "SVN", "goal": "package -U -T 4C source:jar", "url": "http://svn-public.driver.research-infrastructures.eu/driver/dnet45/modules/cnr-misc-utils/trunk/", "deploy_repository": "dnet45-snapshots", "version": "4", "mail": "sandro.labruzzo@isti.cnr.it,michele.artini@isti.cnr.it, claudio.atzori@isti.cnr.it, alessia.bardi@isti.cnr.it", "deploy_repository_url": "http://maven.research-infrastructures.eu/nexus/content/repositories/dnet45-snapshots", "name": "cnr-misc-utils"} |
modules/cnr-misc-utils/tags/cnr-misc-utils-1.0.4/src/main/resources/META-INF/services/javax.xml.transform.TransformerFactory | ||
---|---|---|
1 |
net.sf.saxon.TransformerFactoryImpl |
modules/cnr-misc-utils/tags/cnr-misc-utils-1.0.4/src/main/java/eu/dnetlib/miscutils/factory/Factory.java | ||
---|---|---|
1 |
package eu.dnetlib.miscutils.factory; |
|
2 |
|
|
3 |
/** |
|
4 |
* Provides a common interface for factory objects. |
|
5 |
* |
|
6 |
* @author marko |
|
7 |
* |
|
8 |
* @param <T> |
|
9 |
*/ |
|
10 |
public interface Factory<T> { |
|
11 |
/** |
|
12 |
* returns a new instance. |
|
13 |
* |
|
14 |
* @return |
|
15 |
*/ |
|
16 |
T newInstance(); |
|
17 |
} |
modules/cnr-misc-utils/tags/cnr-misc-utils-1.0.4/src/main/java/eu/dnetlib/miscutils/hstree/TreeNode.java | ||
---|---|---|
1 |
package eu.dnetlib.miscutils.hstree; |
|
2 |
|
|
3 |
import java.lang.reflect.InvocationTargetException; |
|
4 |
import java.lang.reflect.ParameterizedType; |
|
5 |
import java.lang.reflect.Type; |
|
6 |
import java.util.ArrayList; |
|
7 |
import java.util.LinkedList; |
|
8 |
import java.util.List; |
|
9 |
import java.util.Queue; |
|
10 |
|
|
11 |
import org.apache.commons.logging.Log; |
|
12 |
import org.apache.commons.logging.LogFactory; |
|
13 |
|
|
14 |
/** |
|
15 |
* This class implement statically typed complete tree of finite depth. The type signature of each tree node determines |
|
16 |
* fully the depth and the types of all the children. |
|
17 |
* |
|
18 |
* <pre> |
|
19 |
* class MyTree extends TreeNode<RootPayload, L1Payload, TreeNode<L1Payload, L2Payload, TreeNode<L2Payload, Void, NilTreeNode>>> { |
|
20 |
* |
|
21 |
* } |
|
22 |
* </pre> |
|
23 |
* |
|
24 |
* However since java doesn't have type inferencing we'll have to write often the full type of intermediate nodes, |
|
25 |
* especially during tree construction. Thus it's recommended that you split the chain into a number of dummy classes, |
|
26 |
* serving only to the purpuse of declaring the type chain: |
|
27 |
* |
|
28 |
* <pre> |
|
29 |
* class MyTree extends TreeNode<RootPayload, L1Payload, L1Tree> { |
|
30 |
* } |
|
31 |
* |
|
32 |
* class L1Tree extends TreeNode<L1Payload, L2Payload, L2Tree> { |
|
33 |
* } |
|
34 |
* |
|
35 |
* class L2Tree extends TreeNode<L2Payload, Void, NilTreeNode> { |
|
36 |
* } |
|
37 |
* </pre> |
|
38 |
* |
|
39 |
* NOTE: you could keep the whole definition inside a single file using inner classes. |
|
40 |
* |
|
41 |
* @author marko |
|
42 |
* |
|
43 |
* @param <T> |
|
44 |
* Type of the payload (or resource) |
|
45 |
* @param <N> |
|
46 |
* Type of the next level payload |
|
47 |
* @param <C> |
|
48 |
* Type of the next level node (another TreeNode) |
|
49 |
*/ |
|
50 |
public class TreeNode<T, N, V, C extends TreeNode<N, ?, V, ?>> { |
|
51 |
|
|
52 |
public static final String CHILDR_UNDER_LEAF = "cannot create children under leaf nodes"; |
|
53 |
|
|
54 |
private static final Log log = LogFactory.getLog(TreeNode.class); // NOPMD by marko on 11/24/08 5:02 PM |
|
55 |
|
|
56 |
T resource; |
|
57 |
List<C> children = new ArrayList<C>(); |
|
58 |
transient Class<? extends C> childNodeType = autoChildNodeType(getClass()); |
|
59 |
|
|
60 |
/** |
|
61 |
* Default constructor doesn't set the payload. This is used internally to construct a node. We cannot use the |
|
62 |
* <code>TreeNode(T resource)</code> constructor only because it would force any implementor of "alias" subclasses |
|
63 |
* of TreeNode to provide a dummy implementation of the constructor calling <code>super(resource)</code> |
|
64 |
* |
|
65 |
* However the constructor is protected because users should only create objects through <code>addChild</code> or in |
|
66 |
* alternative they should provide they own constructor ovverrides. |
|
67 |
*/ |
|
68 |
protected TreeNode() { |
|
69 |
// no action |
|
70 |
} |
|
71 |
|
|
72 |
/** |
|
73 |
* However the constructor is protected because users should only create objects through <code>addChild</code> or in |
|
74 |
* alternative they should provide they own constructor ovverrides. |
|
75 |
* |
|
76 |
* @param resource |
|
77 |
* payload |
|
78 |
*/ |
|
79 |
protected TreeNode(final T resource) { |
|
80 |
this.resource = resource; |
|
81 |
} |
|
82 |
|
|
83 |
/** |
|
84 |
* Call this method to add a child node. |
|
85 |
* |
|
86 |
* Only the payload is needed, the tree node will be constructed automatically and it will be returned. |
|
87 |
* |
|
88 |
* <pre> |
|
89 |
* L1Child c1 = root.addChild(new L1Resource()); |
|
90 |
* c1.addChild(new L2Resource()); |
|
91 |
* c1.addChild(new L2Resource()).addChild(new L3Resource()); |
|
92 |
* </pre> |
|
93 |
* |
|
94 |
* @param resource |
|
95 |
* payload |
|
96 |
* @return the new node |
|
97 |
*/ |
|
98 |
@SuppressWarnings("unchecked") |
|
99 |
public C addChild(final N resource) { |
|
100 |
try { |
|
101 |
if (childNodeType.equals(NilTreeNode.class)) |
|
102 |
throw new IllegalStateException(CHILDR_UNDER_LEAF); |
|
103 |
|
|
104 |
C test; |
|
105 |
try { |
|
106 |
test = childNodeType.newInstance(); |
|
107 |
test.setResource(resource); |
|
108 |
} catch (InstantiationException e) { |
|
109 |
/* |
|
110 |
* handle the situation when someone wants to create a one argument constructor hiding the default |
|
111 |
* constructor provided by the base class. Nodes should normally be constructed using addChild but we |
|
112 |
* don't want to force users to do it, and if they do it they shouldn't be punished with obscure |
|
113 |
* InstantiationException caused by our evil usage of reflection. Of course we should do much more here |
|
114 |
* in order to be more robust in the general case. |
|
115 |
*/ |
|
116 |
try { |
|
117 |
test = (C) childNodeType.getConstructors()[0].newInstance(resource); // NOPMD |
|
118 |
} catch (InvocationTargetException e1) { |
|
119 |
throw new IllegalStateException(e1); |
|
120 |
} catch (InstantiationException e1) { |
|
121 |
throw new IllegalStateException(e1); |
|
122 |
} |
|
123 |
} |
|
124 |
|
|
125 |
getChildren().add(test); |
|
126 |
return test; |
|
127 |
} catch (IllegalArgumentException e) { |
|
128 |
throw new IllegalStateException(e); |
|
129 |
} catch (SecurityException e) { |
|
130 |
throw new IllegalStateException(e); |
|
131 |
} catch (IllegalAccessException e) { |
|
132 |
throw new IllegalStateException(e); |
|
133 |
} |
|
134 |
} |
|
135 |
|
|
136 |
/** |
|
137 |
* This method is especially useful for leaf nodes when you want to append several children to the same parent node, |
|
138 |
* without having to declare a temporary variable to hold the parent node (which could have long and ugly type) |
|
139 |
* |
|
140 |
* @param resource |
|
141 |
* @return the parent node |
|
142 |
*/ |
|
143 |
public TreeNode<T, N, V, C> appendChild(final N resource) { |
|
144 |
addChild(resource); |
|
145 |
return this; |
|
146 |
} |
|
147 |
|
|
148 |
/** |
|
149 |
* This method applies a visitor to all nodes in a breadth first fashon |
|
150 |
* |
|
151 |
* Currently null payloads are skipped |
|
152 |
* |
|
153 |
* @see Visitor |
|
154 |
* @param visitor |
|
155 |
*/ |
|
156 |
public void breadthFirst(final V visitor) { |
|
157 |
final Queue<TreeNode<?, ?, V, ?>> queue = new LinkedList<TreeNode<?, ?, V, ?>>(); |
|
158 |
|
|
159 |
queue.add(this); |
|
160 |
while (!queue.isEmpty()) { |
|
161 |
final TreeNode<?, ?, V, ?> current = queue.remove(); |
|
162 |
log.info("visiting " + current); |
|
163 |
current.accept(visitor); |
|
164 |
queue.addAll(current.getChildren()); |
|
165 |
} |
|
166 |
|
|
167 |
} |
|
168 |
|
|
169 |
/** |
|
170 |
* depth first. |
|
171 |
* |
|
172 |
* Currently null payloads are skipped |
|
173 |
* |
|
174 |
* @see Visitor |
|
175 |
* @param Visitor |
|
176 |
*/ |
|
177 |
public void depthFirst(final V visitor) { |
|
178 |
baseDepthFirst(visitor); |
|
179 |
} |
|
180 |
|
|
181 |
public void baseDepthFirst(final V visitor) { |
|
182 |
accept(visitor); |
|
183 |
|
|
184 |
for (C el : children) |
|
185 |
el.baseDepthFirst(visitor); |
|
186 |
} |
|
187 |
|
|
188 |
/** |
|
189 |
* For the curious, this method takes care of retrieving the runtime type information for the tree node element |
|
190 |
* declared for children nodes. |
|
191 |
* |
|
192 |
* Because of java type erasure, this is not strictly needed for making this kind of tree work, but it's needed if |
|
193 |
* we want to enable people typing ugly long signatures and use type aliases as described in the class |
|
194 |
* documentation; otherwise a cast exception would occur. |
|
195 |
* |
|
196 |
* Aargh, any serious language which permits type polymorphysm should have a type alias feature |
|
197 |
* |
|
198 |
* @param clazz |
|
199 |
* the class object of this class |
|
200 |
* @return the class object of the node element describing children |
|
201 |
*/ |
|
202 |
@SuppressWarnings({ "unchecked", "rawtypes"}) |
|
203 |
protected Class<? extends C> autoChildNodeType(final Class<? extends TreeNode> clazz) { |
|
204 |
|
|
205 |
final Type superType = clazz.getGenericSuperclass(); |
|
206 |
|
|
207 |
if (superType instanceof ParameterizedType) { |
|
208 |
final ParameterizedType paramSuperType = (ParameterizedType) superType; |
|
209 |
|
|
210 |
int argumentIndex; |
|
211 |
if (paramSuperType.getRawType() == TreeNode.class) |
|
212 |
argumentIndex = 3; |
|
213 |
else |
|
214 |
argumentIndex = 2; |
|
215 |
|
|
216 |
|
|
217 |
final Type argument = (paramSuperType).getActualTypeArguments()[argumentIndex]; |
|
218 |
|
|
219 |
return getRawType(argument); |
|
220 |
} else { |
|
221 |
return autoChildNodeType((Class<? extends TreeNode>) superType); |
|
222 |
} |
|
223 |
} |
|
224 |
|
|
225 |
@SuppressWarnings("unchecked") |
|
226 |
protected <X> X getRawType(final Type type) { |
|
227 |
if (type instanceof ParameterizedType) |
|
228 |
return (X) ((ParameterizedType) type).getRawType(); |
|
229 |
return (X) type; |
|
230 |
} |
|
231 |
|
|
232 |
public List<C> getChildren() { |
|
233 |
return children; |
|
234 |
} |
|
235 |
|
|
236 |
public void setChildren(final List<C> children) { |
|
237 |
this.children = children; |
|
238 |
} |
|
239 |
|
|
240 |
public T getResource() { |
|
241 |
return resource; |
|
242 |
} |
|
243 |
|
|
244 |
public void setResource(final T resource) { |
|
245 |
this.resource = resource; |
|
246 |
} |
|
247 |
|
|
248 |
public void accept(final V dummy) { |
|
249 |
log.fatal("should be ovverriden"); |
|
250 |
} |
|
251 |
|
|
252 |
} |
modules/cnr-misc-utils/tags/cnr-misc-utils-1.0.4/src/main/java/eu/dnetlib/miscutils/hstree/NilTreeNode.java | ||
---|---|---|
1 |
package eu.dnetlib.miscutils.hstree; |
|
2 |
|
|
3 |
/** |
|
4 |
* This is the terminator node in a tree definition chain: |
|
5 |
* |
|
6 |
* TreeNode<L0, L1, TreeNode<L1, L2, TreeNode<L2, Void, NilTreeNode>>> |
|
7 |
* |
|
8 |
* Note the use of "Void" as the next-resource-parameter value in the last level. |
|
9 |
* |
|
10 |
* |
|
11 |
* @author marko |
|
12 |
* |
|
13 |
*/ |
|
14 |
abstract public class NilTreeNode<V> extends TreeNode<Void, Void, V, TreeNode<Void, ?, V, ?>> { // NOPMD |
|
15 |
|
|
16 |
} |
modules/cnr-misc-utils/tags/cnr-misc-utils-1.0.4/src/main/java/eu/dnetlib/miscutils/datetime/DateUtils.java | ||
---|---|---|
1 |
package eu.dnetlib.miscutils.datetime; |
|
2 |
|
|
3 |
import java.text.ParseException; |
|
4 |
import java.text.SimpleDateFormat; |
|
5 |
import java.util.Date; |
|
6 |
import java.util.Locale; |
|
7 |
|
|
8 |
/** |
|
9 |
* various date utilities. |
|
10 |
* |
|
11 |
* @author michele |
|
12 |
* |
|
13 |
*/ |
|
14 |
public class DateUtils { |
|
15 |
|
|
16 |
private static final SimpleDateFormat ISO8601FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US); |
|
17 |
|
|
18 |
private transient final Date date; |
|
19 |
|
|
20 |
public DateUtils() { |
|
21 |
this.date = new Date(); |
|
22 |
} |
|
23 |
|
|
24 |
public DateUtils(final Date date) { |
|
25 |
this.date = (Date) date.clone(); |
|
26 |
} |
|
27 |
|
|
28 |
public String getDateAsISO8601String() { |
|
29 |
String result; |
|
30 |
synchronized (ISO8601FORMAT) { |
|
31 |
result = ISO8601FORMAT.format(this.date); |
|
32 |
} |
|
33 |
|
|
34 |
//convert YYYYMMDDTHH:mm:ss+HH00 into YYYYMMDDTHH:mm:ss+HH:00 |
|
35 |
//- note the added colon for the Timezone |
|
36 |
return result.substring(0, result.length() - 2) + ":" + result.substring(result.length() - 2); |
|
37 |
} |
|
38 |
|
|
39 |
public Long getPrecisionTime() { |
|
40 |
return this.date.getTime(); |
|
41 |
} |
|
42 |
|
|
43 |
public static long now() { |
|
44 |
return new Date().getTime(); |
|
45 |
} |
|
46 |
|
|
47 |
public static String now_ISO8601() { // NOPMD |
|
48 |
String result; |
|
49 |
synchronized (ISO8601FORMAT) { |
|
50 |
result = ISO8601FORMAT.format(new Date()); |
|
51 |
} |
|
52 |
//convert YYYYMMDDTHH:mm:ss+HH00 into YYYYMMDDTHH:mm:ss+HH:00 |
|
53 |
//- note the added colon for the Timezone |
|
54 |
return result.substring(0, result.length() - 2) + ":" + result.substring(result.length() - 2); |
|
55 |
} |
|
56 |
|
|
57 |
/** |
|
58 |
* parses a iso8601 date into a date. |
|
59 |
* |
|
60 |
* @param date |
|
61 |
* string iso8601 date |
|
62 |
* @return date object |
|
63 |
*/ |
|
64 |
public Date parse(final String dateArg) { |
|
65 |
String date = dateArg; |
|
66 |
|
|
67 |
if ("".equals(date)) |
|
68 |
return null; |
|
69 |
|
|
70 |
try { |
|
71 |
if (date.endsWith("Z")) { |
|
72 |
date = date.replace("Z", "+0000"); |
|
73 |
} else if (date.length() < 20) { |
|
74 |
date += "+0000"; // NOPMD |
|
75 |
} else { |
|
76 |
final String end = date.substring(date.length() - 3); |
|
77 |
date = date.substring(0, date.length() - 3) + end.replace(":", ""); |
|
78 |
} |
|
79 |
|
|
80 |
synchronized (ISO8601FORMAT) { |
|
81 |
return ISO8601FORMAT.parse(date); |
|
82 |
} |
|
83 |
} catch (ParseException e) { |
|
84 |
throw new IllegalStateException("invalid iso8601 date '" + dateArg + "' (even after normalizing it to '" + date + "')"); |
|
85 |
} |
|
86 |
} |
|
87 |
|
|
88 |
public static String calculate_ISO8601(long l) { |
|
89 |
String result = ISO8601FORMAT.format(new Date(l)); |
|
90 |
// convert YYYYMMDDTHH:mm:ss+HH00 into YYYYMMDDTHH:mm:ss+HH:00 |
|
91 |
//- note the added colon for the Timezone |
|
92 |
result = result.substring(0, result.length() - 2) + ":" + result.substring(result.length() - 2); |
|
93 |
return result; |
|
94 |
} |
|
95 |
|
|
96 |
/** |
|
97 |
* Extracts the duration part of a ISO8601 formatted date. Duration part is the part after the 'T'. |
|
98 |
* |
|
99 |
* @param dateArg |
|
100 |
* @return |
|
101 |
*/ |
|
102 |
public String getDuration(final String dateArg) { |
|
103 |
String[] splitted = dateArg.split("T"); |
|
104 |
if (splitted.length == 1) |
|
105 |
return "0"; |
|
106 |
else |
|
107 |
return splitted[1]; |
|
108 |
} |
|
109 |
} |
modules/cnr-misc-utils/tags/cnr-misc-utils-1.0.4/src/main/java/eu/dnetlib/miscutils/datetime/HumanTime.java | ||
---|---|---|
1 |
package eu.dnetlib.miscutils.datetime; |
|
2 |
|
|
3 |
/* |
|
4 |
* HumanTime.java |
|
5 |
* |
|
6 |
* Created on 06.10.2008 |
|
7 |
* |
|
8 |
* Copyright (c) 2008 Johann Burkard (<mailto:jb@eaio.com>) <http://eaio.com> |
|
9 |
* |
|
10 |
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated |
|
11 |
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the |
|
12 |
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to |
|
13 |
* permit persons to whom the Software is furnished to do so, subject to the following conditions: |
|
14 |
* |
|
15 |
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the |
|
16 |
* Software. |
|
17 |
* |
|
18 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
|
19 |
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
|
20 |
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
21 |
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
22 |
* |
|
23 |
*/ |
|
24 |
|
|
25 |
import java.io.Externalizable; |
|
26 |
import java.io.IOException; |
|
27 |
import java.io.ObjectInput; |
|
28 |
import java.io.ObjectOutput; |
|
29 |
import java.util.Iterator; |
|
30 |
|
|
31 |
/** |
|
32 |
* HumanTime parses and formats time deltas for easier reading by humans. It can format time information without losing |
|
33 |
* information but its main purpose is to generate more easily understood approximations. <h3>Using HumanTime</h3> |
|
34 |
* <p> |
|
35 |
* Use HumanTime by creating an instance that contains the time delta ({@link HumanTime#HumanTime(long)}), create an |
|
36 |
* empty instance through ({@link HumanTime#HumanTime()}) and set the delta using the {@link #y()}, {@link #d()}, |
|
37 |
* {@link #h()}, {@link #s()} and {@link #ms()} methods or parse a {@link CharSequence} representation ( |
|
38 |
* {@link #eval(CharSequence)}). Parsing ignores whitespace and is case insensitive. |
|
39 |
* </p> |
|
40 |
* <h3>HumanTime format</h3> |
|
41 |
* <p> |
|
42 |
* HumanTime will format time deltas in years ("y"), days ("d"), hours ("h"), minutes ("m"), seconds ("s") and |
|
43 |
* milliseconds ("ms"), separated by a blank character. For approximate representations, the time delta will be round up |
|
44 |
* or down if necessary. |
|
45 |
* </p> |
|
46 |
* <h3>HumanTime examples</h3> |
|
47 |
* <ul> |
|
48 |
* <li>HumanTime.eval("1 d 1d 2m 3m").getExactly() = "2 d 5 m"</li> |
|
49 |
* <li>HumanTime.eval("2m8d2h4m").getExactly() = "8 d 2 h 6 m"</li> |
|
50 |
* <li>HumanTime.approximately("2 d 8 h 20 m 50 s") = "2 d 8 h"</li> |
|
51 |
* <li>HumanTime.approximately("55m") = "1 h"</li> |
|
52 |
* </ul> |
|
53 |
* <h3>Implementation details</h3> |
|
54 |
* <ul> |
|
55 |
* <li>The time delta can only be increased.</li> |
|
56 |
* <li>Instances of this class are thread safe.</li> |
|
57 |
* <li>Getters using the Java Beans naming conventions are provided for use in environments like JSP or with expression |
|
58 |
* languages like OGNL. See {@link #getApproximately()} and {@link #getExactly()}.</li> |
|
59 |
* <li>To keep things simple, a year consists of 365 days.</li> |
|
60 |
* </ul> |
|
61 |
* |
|
62 |
* @author <a href="mailto:jb@eaio.com">Johann Burkard</a> |
|
63 |
* @version $Id: HumanTime.java 323 2008-10-08 19:06:22Z Johann $ |
|
64 |
* @see #eval(CharSequence) |
|
65 |
* @see #approximately(CharSequence) |
|
66 |
* @see <a href="http://johannburkard.de/blog/programming/java/date-formatting-parsing-humans-humantime.html">Date |
|
67 |
* Formatting and Parsing for Humans in Java with HumanTime</a> |
|
68 |
*/ |
|
69 |
public class HumanTime implements Externalizable, Comparable<HumanTime>, Cloneable { |
|
70 |
|
|
71 |
/** |
|
72 |
* The serial version UID. |
|
73 |
*/ |
|
74 |
private static final long serialVersionUID = 5179328390732826722L; |
|
75 |
|
|
76 |
/** |
|
77 |
* One second. |
|
78 |
*/ |
|
79 |
private static final long SECOND = 1000; |
|
80 |
|
|
81 |
/** |
|
82 |
* One minute. |
|
83 |
*/ |
|
84 |
private static final long MINUTE = SECOND * 60; |
|
85 |
|
|
86 |
/** |
|
87 |
* One hour. |
|
88 |
*/ |
|
89 |
private static final long HOUR = MINUTE * 60; |
|
90 |
|
|
91 |
/** |
|
92 |
* One day. |
|
93 |
*/ |
|
94 |
private static final long DAY = HOUR * 24; |
|
95 |
|
|
96 |
/** |
|
97 |
* One year. |
|
98 |
*/ |
|
99 |
private static final long YEAR = DAY * 365; |
|
100 |
|
|
101 |
/** |
|
102 |
* Percentage of what is round up or down. |
|
103 |
*/ |
|
104 |
private static final int CEILING_PERCENTAGE = 15; |
|
105 |
|
|
106 |
/** |
|
107 |
* Parsing state. |
|
108 |
*/ |
|
109 |
static enum State { |
|
110 |
|
|
111 |
NUMBER, IGNORED, UNIT |
|
112 |
|
|
113 |
} |
|
114 |
|
|
115 |
static State getState(char c) { |
|
116 |
State out; |
|
117 |
switch (c) { |
|
118 |
case '0': |
|
119 |
case '1': |
|
120 |
case '2': |
|
121 |
case '3': |
|
122 |
case '4': |
|
123 |
case '5': |
|
124 |
case '6': |
|
125 |
case '7': |
|
126 |
case '8': |
|
127 |
case '9': |
|
128 |
out = State.NUMBER; |
|
129 |
break; |
|
130 |
case 's': |
|
131 |
case 'm': |
|
132 |
case 'h': |
|
133 |
case 'd': |
|
134 |
case 'y': |
|
135 |
case 'S': |
|
136 |
case 'M': |
|
137 |
case 'H': |
|
138 |
case 'D': |
|
139 |
case 'Y': |
|
140 |
out = State.UNIT; |
|
141 |
break; |
|
142 |
default: |
|
143 |
out = State.IGNORED; |
|
144 |
} |
|
145 |
return out; |
|
146 |
} |
|
147 |
|
|
148 |
/** |
|
149 |
* Parses a {@link CharSequence} argument and returns a {@link HumanTime} instance. |
|
150 |
* |
|
151 |
* @param s |
|
152 |
* the char sequence, may not be <code>null</code> |
|
153 |
* @return an instance, never <code>null</code> |
|
154 |
*/ |
|
155 |
public static HumanTime eval(final CharSequence s) { |
|
156 |
HumanTime out = new HumanTime(0L); |
|
157 |
|
|
158 |
int num = 0; |
|
159 |
|
|
160 |
int start = 0; |
|
161 |
int end = 0; |
|
162 |
|
|
163 |
State oldState = State.IGNORED; |
|
164 |
|
|
165 |
for (char c : new Iterable<Character>() { |
|
166 |
|
|
167 |
/** |
|
168 |
* @see java.lang.Iterable#iterator() |
|
169 |
*/ |
|
170 |
@Override |
|
171 |
public Iterator<Character> iterator() { |
|
172 |
return new Iterator<Character>() { |
|
173 |
|
|
174 |
private int p = 0; |
|
175 |
|
|
176 |
/** |
|
177 |
* @see java.util.Iterator#hasNext() |
|
178 |
*/ |
|
179 |
@Override |
|
180 |
public boolean hasNext() { |
|
181 |
return p < s.length(); |
|
182 |
} |
|
183 |
|
|
184 |
/** |
|
185 |
* @see java.util.Iterator#next() |
|
186 |
*/ |
|
187 |
@Override |
|
188 |
public Character next() { |
|
189 |
return s.charAt(p++); |
|
190 |
} |
|
191 |
|
|
192 |
/** |
|
193 |
* @see java.util.Iterator#remove() |
|
194 |
*/ |
|
195 |
@Override |
|
196 |
public void remove() { |
|
197 |
throw new UnsupportedOperationException(); |
|
198 |
} |
|
199 |
|
|
200 |
}; |
|
201 |
} |
|
202 |
|
|
203 |
}) { |
|
204 |
State newState = getState(c); |
|
205 |
if (oldState != newState) { |
|
206 |
if (oldState == State.NUMBER && (newState == State.IGNORED || newState == State.UNIT)) { |
|
207 |
num = Integer.parseInt(s.subSequence(start, end).toString()); |
|
208 |
} else if (oldState == State.UNIT && (newState == State.IGNORED || newState == State.NUMBER)) { |
|
209 |
out.nTimes(s.subSequence(start, end).toString(), num); |
|
210 |
num = 0; |
|
211 |
} |
|
212 |
start = end; |
|
213 |
} |
|
214 |
++end; |
|
215 |
oldState = newState; |
|
216 |
} |
|
217 |
if (oldState == State.UNIT) { |
|
218 |
out.nTimes(s.subSequence(start, end).toString(), num); |
|
219 |
} |
|
220 |
|
|
221 |
return out; |
|
222 |
} |
|
223 |
|
|
224 |
/** |
|
225 |
* Parses and formats the given char sequence, preserving all data. |
|
226 |
* <p> |
|
227 |
* Equivalent to <code>eval(in).getExactly()</code> |
|
228 |
* |
|
229 |
* @param in |
|
230 |
* the char sequence, may not be <code>null</code> |
|
231 |
* @return a formatted String, never <code>null</code> |
|
232 |
*/ |
|
233 |
public static String exactly(CharSequence in) { |
|
234 |
return eval(in).getExactly(); |
|
235 |
} |
|
236 |
|
|
237 |
/** |
|
238 |
* Formats the given time delta, preserving all data. |
|
239 |
* <p> |
|
240 |
* Equivalent to <code>new HumanTime(in).getExactly()</code> |
|
241 |
* |
|
242 |
* @param l |
|
243 |
* the time delta |
|
244 |
* @return a formatted String, never <code>null</code> |
|
245 |
*/ |
|
246 |
public static String exactly(long l) { |
|
247 |
return new HumanTime(l).getExactly(); |
|
248 |
} |
|
249 |
|
|
250 |
/** |
|
251 |
* Parses and formats the given char sequence, potentially removing some data to make the output easier to |
|
252 |
* understand. |
|
253 |
* <p> |
|
254 |
* Equivalent to <code>eval(in).getApproximately()</code> |
|
255 |
* |
|
256 |
* @param in |
|
257 |
* the char sequence, may not be <code>null</code> |
|
258 |
* @return a formatted String, never <code>null</code> |
|
259 |
*/ |
|
260 |
public static String approximately(CharSequence in) { |
|
261 |
return eval(in).getApproximately(); |
|
262 |
} |
|
263 |
|
|
264 |
/** |
|
265 |
* Formats the given time delta, preserving all data. |
|
266 |
* <p> |
|
267 |
* Equivalent to <code>new HumanTime(l).getApproximately()</code> |
|
268 |
* |
|
269 |
* @param l |
|
270 |
* the time delta |
|
271 |
* @return a formatted String, never <code>null</code> |
|
272 |
*/ |
|
273 |
public static String approximately(long l) { |
|
274 |
return new HumanTime(l).getApproximately(); |
|
275 |
} |
|
276 |
|
|
277 |
/** |
|
278 |
* The time delta. |
|
279 |
*/ |
|
280 |
private long delta; |
|
281 |
|
|
282 |
/** |
|
283 |
* No-argument Constructor for HumanTime. |
|
284 |
* <p> |
|
285 |
* Equivalent to calling <code>new HumanTime(0L)</code>. |
|
286 |
*/ |
|
287 |
public HumanTime() { |
|
288 |
this(0L); |
|
289 |
} |
|
290 |
|
|
291 |
/** |
|
292 |
* Constructor for HumanTime. |
|
293 |
* |
|
294 |
* @param delta |
|
295 |
* the initial time delta, interpreted as a positive number |
|
296 |
*/ |
|
297 |
public HumanTime(long delta) { |
|
298 |
super(); |
|
299 |
this.delta = Math.abs(delta); |
|
300 |
} |
|
301 |
|
|
302 |
private void nTimes(String unit, int n) { |
|
303 |
if ("ms".equalsIgnoreCase(unit)) { |
|
304 |
ms(n); |
|
305 |
} else if ("s".equalsIgnoreCase(unit)) { |
|
306 |
s(n); |
|
307 |
} else if ("m".equalsIgnoreCase(unit)) { |
|
308 |
m(n); |
|
309 |
} else if ("h".equalsIgnoreCase(unit)) { |
|
310 |
h(n); |
|
311 |
} else if ("d".equalsIgnoreCase(unit)) { |
|
312 |
d(n); |
|
313 |
} else if ("y".equalsIgnoreCase(unit)) { |
|
314 |
y(n); |
|
315 |
} |
|
316 |
} |
|
317 |
|
|
318 |
private long upperCeiling(long x) { |
|
319 |
return (x / 100) * (100 - CEILING_PERCENTAGE); |
|
320 |
} |
|
321 |
|
|
322 |
private long lowerCeiling(long x) { |
|
323 |
return (x / 100) * CEILING_PERCENTAGE; |
|
324 |
} |
|
325 |
|
|
326 |
private String ceil(long d, long n) { |
|
327 |
return Integer.toString((int) Math.ceil((double) d / n)); |
|
328 |
} |
|
329 |
|
|
330 |
private String floor(long d, long n) { |
|
331 |
return Integer.toString((int) Math.floor((double) d / n)); |
|
332 |
} |
|
333 |
|
|
334 |
/** |
|
335 |
* Adds one year to the time delta. |
|
336 |
* |
|
337 |
* @return this HumanTime object |
|
338 |
*/ |
|
339 |
public HumanTime y() { |
|
340 |
return y(1); |
|
341 |
} |
|
342 |
|
|
343 |
/** |
|
344 |
* Adds n years to the time delta. |
|
345 |
* |
|
346 |
* @param n |
|
347 |
* n |
|
348 |
* @return this HumanTime object |
|
349 |
*/ |
|
350 |
public HumanTime y(int n) { |
|
351 |
delta += YEAR * Math.abs(n); |
|
352 |
return this; |
|
353 |
} |
|
354 |
|
|
355 |
/** |
|
356 |
* Adds one day to the time delta. |
|
357 |
* |
|
358 |
* @return this HumanTime object |
|
359 |
*/ |
|
360 |
public HumanTime d() { |
|
361 |
return d(1); |
|
362 |
} |
|
363 |
|
|
364 |
/** |
|
365 |
* Adds n days to the time delta. |
|
366 |
* |
|
367 |
* @param n |
|
368 |
* n |
|
369 |
* @return this HumanTime object |
|
370 |
*/ |
|
371 |
public HumanTime d(int n) { |
|
372 |
delta += DAY * Math.abs(n); |
|
373 |
return this; |
|
374 |
} |
|
375 |
|
|
376 |
/** |
|
377 |
* Adds one hour to the time delta. |
|
378 |
* |
|
379 |
* @return this HumanTime object |
|
380 |
*/ |
|
381 |
public HumanTime h() { |
|
382 |
return h(1); |
|
383 |
} |
|
384 |
|
|
385 |
/** |
|
386 |
* Adds n hours to the time delta. |
|
387 |
* |
|
388 |
* @param n |
|
389 |
* n |
|
390 |
* @return this HumanTime object |
|
391 |
*/ |
|
392 |
public HumanTime h(int n) { |
|
393 |
delta += HOUR * Math.abs(n); |
|
394 |
return this; |
|
395 |
} |
|
396 |
|
|
397 |
/** |
|
398 |
* Adds one month to the time delta. |
|
399 |
* |
|
400 |
* @return this HumanTime object |
|
401 |
*/ |
|
402 |
public HumanTime m() { |
|
403 |
return m(1); |
|
404 |
} |
|
405 |
|
|
406 |
/** |
|
407 |
* Adds n months to the time delta. |
|
408 |
* |
|
409 |
* @param n |
|
410 |
* n |
|
411 |
* @return this HumanTime object |
|
412 |
*/ |
|
413 |
public HumanTime m(int n) { |
|
414 |
delta += MINUTE * Math.abs(n); |
|
415 |
return this; |
|
416 |
} |
|
417 |
|
|
418 |
/** |
|
419 |
* Adds one second to the time delta. |
|
420 |
* |
|
421 |
* @return this HumanTime object |
|
422 |
*/ |
|
423 |
public HumanTime s() { |
|
424 |
return s(1); |
|
425 |
} |
|
426 |
|
|
427 |
/** |
|
428 |
* Adds n seconds to the time delta. |
|
429 |
* |
|
430 |
* @param n |
|
431 |
* seconds |
|
432 |
* @return this HumanTime object |
|
433 |
*/ |
|
434 |
public HumanTime s(int n) { |
|
435 |
delta += SECOND * Math.abs(n); |
|
436 |
return this; |
|
437 |
} |
|
438 |
|
|
439 |
/** |
|
440 |
* Adds one millisecond to the time delta. |
|
441 |
* |
|
442 |
* @return this HumanTime object |
|
443 |
*/ |
|
444 |
public HumanTime ms() { |
|
445 |
return ms(1); |
|
446 |
} |
|
447 |
|
|
448 |
/** |
|
449 |
* Adds n milliseconds to the time delta. |
|
450 |
* |
|
451 |
* @param n |
|
452 |
* n |
|
453 |
* @return this HumanTime object |
|
454 |
*/ |
|
455 |
public HumanTime ms(int n) { |
|
456 |
delta += Math.abs(n); |
|
457 |
return this; |
|
458 |
} |
|
459 |
|
|
460 |
/** |
|
461 |
* Returns a human-formatted representation of the time delta. |
|
462 |
* |
|
463 |
* @return a formatted representation of the time delta, never <code>null</code> |
|
464 |
*/ |
|
465 |
public String getExactly() { |
|
466 |
return getExactly(new StringBuilder()).toString(); |
|
467 |
} |
|
468 |
|
|
469 |
/** |
|
470 |
* Appends a human-formatted representation of the time delta to the given {@link Appendable} object. |
|
471 |
* |
|
472 |
* @param <T> |
|
473 |
* the return type |
|
474 |
* @param a |
|
475 |
* the Appendable object, may not be <code>null</code> |
|
476 |
* @return the given Appendable object, never <code>null</code> |
|
477 |
*/ |
|
478 |
public <T extends Appendable> T getExactly(T a) { |
|
479 |
try { |
|
480 |
boolean prependBlank = false; |
|
481 |
long d = delta; |
|
482 |
if (d >= YEAR) { |
|
483 |
a.append(floor(d, YEAR)); |
|
484 |
a.append(' '); |
|
485 |
a.append('y'); |
|
486 |
prependBlank = true; |
|
487 |
} |
|
488 |
d %= YEAR; |
|
489 |
if (d >= DAY) { |
|
490 |
if (prependBlank) { |
|
491 |
a.append(' '); |
|
492 |
} |
|
493 |
a.append(floor(d, DAY)); |
|
494 |
a.append(' '); |
|
495 |
a.append('d'); |
|
496 |
prependBlank = true; |
|
497 |
} |
|
498 |
d %= DAY; |
|
499 |
if (d >= HOUR) { |
|
500 |
if (prependBlank) { |
|
501 |
a.append(' '); |
|
502 |
} |
|
503 |
a.append(floor(d, HOUR)); |
|
504 |
a.append(' '); |
|
505 |
a.append('h'); |
|
506 |
prependBlank = true; |
|
507 |
} |
|
508 |
d %= HOUR; |
|
509 |
if (d >= MINUTE) { |
|
510 |
if (prependBlank) { |
|
511 |
a.append(' '); |
|
512 |
} |
|
513 |
a.append(floor(d, MINUTE)); |
|
514 |
a.append(' '); |
|
515 |
a.append('m'); |
|
516 |
prependBlank = true; |
|
517 |
} |
|
518 |
d %= MINUTE; |
|
519 |
if (d >= SECOND) { |
|
520 |
if (prependBlank) { |
|
521 |
a.append(' '); |
|
522 |
} |
|
523 |
a.append(floor(d, SECOND)); |
|
524 |
a.append(' '); |
|
525 |
a.append('s'); |
|
526 |
prependBlank = true; |
|
527 |
} |
|
528 |
d %= SECOND; |
|
529 |
if (d > 0) { |
|
530 |
if (prependBlank) { |
|
531 |
a.append(' '); |
|
532 |
} |
|
533 |
a.append(Integer.toString((int) d)); |
|
534 |
a.append(' '); |
|
535 |
a.append('m'); |
|
536 |
a.append('s'); |
|
537 |
} |
|
538 |
} catch (IOException ex) { |
|
539 |
// What were they thinking... |
|
540 |
} |
|
541 |
return a; |
|
542 |
} |
|
543 |
|
|
544 |
/** |
|
545 |
* Returns an approximate, human-formatted representation of the time delta. |
|
546 |
* |
|
547 |
* @return a formatted representation of the time delta, never <code>null</code> |
|
548 |
*/ |
|
549 |
public String getApproximately() { |
|
550 |
return getApproximately(new StringBuilder()).toString(); |
|
551 |
} |
|
552 |
|
|
553 |
/** |
|
554 |
* Appends an approximate, human-formatted representation of the time delta to the given {@link Appendable} object. |
|
555 |
* |
|
556 |
* @param <T> |
|
557 |
* the return type |
|
558 |
* @param a |
|
559 |
* the Appendable object, may not be <code>null</code> |
|
560 |
* @return the given Appendable object, never <code>null</code> |
|
561 |
*/ |
|
562 |
public <T extends Appendable> T getApproximately(T a) { |
|
563 |
|
|
564 |
try { |
|
565 |
int parts = 0; |
|
566 |
boolean rounded = false; |
|
567 |
boolean prependBlank = false; |
|
568 |
long d = delta; |
|
569 |
long mod = d % YEAR; |
|
570 |
|
|
571 |
if (mod >= upperCeiling(YEAR)) { |
|
572 |
a.append(ceil(d, YEAR)); |
|
573 |
a.append(' '); |
|
574 |
a.append('y'); |
|
575 |
++parts; |
|
576 |
rounded = true; |
|
577 |
prependBlank = true; |
|
578 |
} else if (d >= YEAR) { |
|
579 |
a.append(floor(d, YEAR)); |
|
580 |
a.append(' '); |
|
581 |
a.append('y'); |
|
582 |
++parts; |
|
583 |
rounded = mod <= lowerCeiling(YEAR); |
|
584 |
prependBlank = true; |
|
585 |
} |
|
586 |
|
|
587 |
if (!rounded) { |
|
588 |
d %= YEAR; |
|
589 |
mod = d % DAY; |
|
590 |
|
|
591 |
if (mod >= upperCeiling(DAY)) { |
|
592 |
if (prependBlank) { |
|
593 |
a.append(' '); |
|
594 |
} |
|
595 |
a.append(ceil(d, DAY)); |
|
596 |
a.append(' '); |
|
597 |
a.append('d'); |
|
598 |
++parts; |
|
599 |
rounded = true; |
|
600 |
prependBlank = true; |
|
601 |
} else if (d >= DAY) { |
|
602 |
if (prependBlank) { |
|
603 |
a.append(' '); |
|
604 |
} |
|
605 |
a.append(floor(d, DAY)); |
|
606 |
a.append(' '); |
|
607 |
a.append('d'); |
|
608 |
++parts; |
|
609 |
rounded = mod <= lowerCeiling(DAY); |
|
610 |
prependBlank = true; |
|
611 |
} |
|
612 |
|
|
613 |
if (parts < 2) { |
|
614 |
d %= DAY; |
|
615 |
mod = d % HOUR; |
|
616 |
|
|
617 |
if (mod >= upperCeiling(HOUR)) { |
|
618 |
if (prependBlank) { |
|
619 |
a.append(' '); |
|
620 |
} |
|
621 |
a.append(ceil(d, HOUR)); |
|
622 |
a.append(' '); |
|
623 |
a.append('h'); |
|
624 |
++parts; |
|
625 |
rounded = true; |
|
626 |
prependBlank = true; |
|
627 |
} else if (d >= HOUR && !rounded) { |
|
628 |
if (prependBlank) { |
|
629 |
a.append(' '); |
|
630 |
} |
|
631 |
a.append(floor(d, HOUR)); |
|
632 |
a.append(' '); |
|
633 |
a.append('h'); |
|
634 |
++parts; |
|
635 |
rounded = mod <= lowerCeiling(HOUR); |
|
636 |
prependBlank = true; |
|
637 |
} |
|
638 |
|
|
639 |
if (parts < 2) { |
|
640 |
d %= HOUR; |
|
641 |
mod = d % MINUTE; |
|
642 |
|
|
643 |
if (mod >= upperCeiling(MINUTE)) { |
|
644 |
if (prependBlank) { |
|
645 |
a.append(' '); |
|
646 |
} |
|
647 |
a.append(ceil(d, MINUTE)); |
|
648 |
a.append(' '); |
|
649 |
a.append('m'); |
|
650 |
++parts; |
|
651 |
rounded = true; |
|
652 |
prependBlank = true; |
|
653 |
} else if (d >= MINUTE && !rounded) { |
|
654 |
if (prependBlank) { |
|
655 |
a.append(' '); |
|
656 |
} |
|
657 |
a.append(floor(d, MINUTE)); |
|
658 |
a.append(' '); |
|
659 |
a.append('m'); |
|
660 |
++parts; |
|
661 |
rounded = mod <= lowerCeiling(MINUTE); |
|
662 |
prependBlank = true; |
|
663 |
} |
|
664 |
|
|
665 |
if (parts < 2) { |
|
666 |
d %= MINUTE; |
|
667 |
mod = d % SECOND; |
|
668 |
|
|
669 |
if (mod >= upperCeiling(SECOND)) { |
|
670 |
if (prependBlank) { |
|
671 |
a.append(' '); |
|
672 |
} |
|
673 |
a.append(ceil(d, SECOND)); |
|
674 |
a.append(' '); |
|
675 |
a.append('s'); |
|
676 |
++parts; |
|
677 |
rounded = true; |
|
678 |
prependBlank = true; |
|
679 |
} else if (d >= SECOND && !rounded) { |
|
680 |
if (prependBlank) { |
|
681 |
a.append(' '); |
|
682 |
} |
|
683 |
a.append(floor(d, SECOND)); |
|
684 |
a.append(' '); |
|
685 |
a.append('s'); |
|
686 |
++parts; |
|
687 |
rounded = mod <= lowerCeiling(SECOND); |
|
688 |
prependBlank = true; |
|
689 |
} |
|
690 |
|
|
691 |
if (parts < 2) { |
|
692 |
d %= SECOND; |
|
693 |
|
|
694 |
if (d > 0 && !rounded) { |
|
695 |
if (prependBlank) { |
|
696 |
a.append(' '); |
|
697 |
} |
|
698 |
a.append(Integer.toString((int) d)); |
|
699 |
a.append(' '); |
|
700 |
a.append('m'); |
|
701 |
a.append('s'); |
|
702 |
} |
|
703 |
} |
|
704 |
|
|
705 |
} |
|
706 |
|
|
707 |
} |
|
708 |
|
|
709 |
} |
|
710 |
} |
|
711 |
} catch (IOException ex) { |
|
712 |
// What were they thinking... |
|
713 |
} |
|
714 |
|
|
715 |
return a; |
|
716 |
} |
|
717 |
|
|
718 |
/** |
|
719 |
* Returns the time delta. |
|
720 |
* |
|
721 |
* @return the time delta |
|
722 |
*/ |
|
723 |
public long getDelta() { |
|
724 |
return delta; |
|
725 |
} |
|
726 |
|
|
727 |
/** |
|
728 |
* @see java.lang.Object#equals(java.lang.Object) |
|
729 |
*/ |
|
730 |
@Override |
|
731 |
public boolean equals(Object obj) { |
|
732 |
if (this == obj) { |
|
733 |
return true; |
|
734 |
} |
|
735 |
if (!(obj instanceof HumanTime)) { |
|
736 |
return false; |
|
737 |
} |
|
738 |
return delta == ((HumanTime) obj).delta; |
|
739 |
} |
|
740 |
|
|
741 |
/** |
|
742 |
* Returns a 32-bit representation of the time delta. |
|
743 |
* |
|
744 |
* @see java.lang.Object#hashCode() |
|
745 |
*/ |
|
746 |
@Override |
|
747 |
public int hashCode() { |
|
748 |
return (int) (delta ^ (delta >> 32)); |
|
749 |
} |
|
750 |
|
|
751 |
/** |
|
752 |
* Returns a String representation of this. |
|
753 |
* <p> |
|
754 |
* The output is identical to {@link #getExactly()}. |
|
755 |
* |
|
756 |
* @see java.lang.Object#toString() |
|
757 |
* @see #getExactly() |
|
758 |
* @return a String, never <code>null</code> |
|
759 |
*/ |
|
760 |
@Override |
|
761 |
public String toString() { |
|
762 |
return getExactly(); |
|
763 |
} |
|
764 |
|
|
765 |
/** |
|
766 |
* Compares this HumanTime to another HumanTime. |
|
767 |
* |
|
768 |
* @param t |
|
769 |
* the other instance, may not be <code>null</code> |
|
770 |
* @return which one is greater |
|
771 |
*/ |
|
772 |
@Override |
|
773 |
public int compareTo(HumanTime t) { |
|
774 |
return delta == t.delta ? 0 : (delta < t.delta ? -1 : 1); |
|
775 |
} |
|
776 |
|
|
777 |
/** |
|
778 |
* Deep-clones this object. |
|
779 |
* |
|
780 |
* @see java.lang.Object#clone() |
|
781 |
* @throws CloneNotSupportedException |
|
782 |
*/ |
|
783 |
@Override |
|
784 |
public Object clone() throws CloneNotSupportedException { |
|
785 |
return super.clone(); |
|
786 |
} |
|
787 |
|
|
788 |
/** |
|
789 |
* @see java.io.Externalizable#readExternal(java.io.ObjectInput) |
|
790 |
*/ |
|
791 |
@Override |
|
792 |
public void readExternal(ObjectInput in) throws IOException { |
|
793 |
delta = in.readLong(); |
|
794 |
} |
|
795 |
|
|
796 |
/** |
|
797 |
* @see java.io.Externalizable#writeExternal(java.io.ObjectOutput) |
|
798 |
*/ |
|
799 |
@Override |
|
800 |
public void writeExternal(ObjectOutput out) throws IOException { |
|
801 |
out.writeLong(delta); |
|
802 |
} |
|
803 |
|
|
804 |
} |
modules/cnr-misc-utils/tags/cnr-misc-utils-1.0.4/src/main/java/eu/dnetlib/miscutils/iterators/xml/IterableXmlParser.java | ||
---|---|---|
1 |
package eu.dnetlib.miscutils.iterators.xml; |
|
2 |
|
|
3 |
import java.io.ByteArrayInputStream; |
|
4 |
import java.io.InputStream; |
|
5 |
import java.nio.charset.Charset; |
|
6 |
import java.util.Iterator; |
|
7 |
|
|
8 |
public class IterableXmlParser implements Iterable<String> { |
|
9 |
|
|
10 |
private String element; |
|
11 |
|
|
12 |
private InputStream inputStream; |
|
13 |
|
|
14 |
public IterableXmlParser(String element, InputStream inputStream) { |
|
15 |
this.element = element; |
|
16 |
this.inputStream = inputStream; |
|
17 |
} |
|
18 |
|
|
19 |
public IterableXmlParser(String element, String xml) { |
|
20 |
this.element = element; |
|
21 |
this.inputStream = new ByteArrayInputStream(xml.getBytes(Charset.forName(XMLIterator.UTF_8))); |
|
22 |
} |
|
23 |
|
|
24 |
@Override |
|
25 |
public Iterator<String> iterator() { |
|
26 |
return new XMLIterator(element, inputStream); |
|
27 |
} |
|
28 |
|
|
29 |
} |
modules/cnr-misc-utils/tags/cnr-misc-utils-1.0.4/src/main/java/eu/dnetlib/miscutils/iterators/xml/XMLIterator.java | ||
---|---|---|
1 |
package eu.dnetlib.miscutils.iterators.xml; |
|
2 |
|
|
3 |
import java.io.InputStream; |
|
4 |
import java.io.InputStreamReader; |
|
5 |
import java.io.Reader; |
|
6 |
import java.io.StringWriter; |
|
7 |
import java.nio.charset.Charset; |
|
8 |
import java.nio.charset.CharsetDecoder; |
|
9 |
import java.nio.charset.CodingErrorAction; |
|
10 |
import java.util.Iterator; |
|
11 |
|
|
12 |
import javax.xml.stream.XMLEventFactory; |
|
13 |
import javax.xml.stream.XMLEventReader; |
|
14 |
import javax.xml.stream.XMLEventWriter; |
|
15 |
import javax.xml.stream.XMLInputFactory; |
|
16 |
import javax.xml.stream.XMLOutputFactory; |
|
17 |
import javax.xml.stream.XMLStreamException; |
|
18 |
import javax.xml.stream.events.StartElement; |
|
19 |
import javax.xml.stream.events.XMLEvent; |
|
20 |
|
|
21 |
import org.apache.commons.logging.Log; |
|
22 |
import org.apache.commons.logging.LogFactory; |
|
23 |
|
|
24 |
public class XMLIterator implements Iterator<String> { |
|
25 |
|
|
26 |
private static final Log log = LogFactory.getLog(XMLIterator.class); |
|
27 |
|
|
28 |
private ThreadLocal<XMLInputFactory> inputFactory = new ThreadLocal<XMLInputFactory>() { |
|
29 |
|
|
30 |
@Override |
|
31 |
protected XMLInputFactory initialValue() { |
|
32 |
return XMLInputFactory.newInstance(); |
|
33 |
} |
|
34 |
}; |
|
35 |
|
|
36 |
private ThreadLocal<XMLOutputFactory> outputFactory = new ThreadLocal<XMLOutputFactory>() { |
|
37 |
|
|
38 |
@Override |
|
39 |
protected XMLOutputFactory initialValue() { |
|
40 |
return XMLOutputFactory.newInstance(); |
|
41 |
} |
|
42 |
}; |
|
43 |
|
|
44 |
private ThreadLocal<XMLEventFactory> eventFactory = new ThreadLocal<XMLEventFactory>() { |
|
45 |
|
|
46 |
@Override |
|
47 |
protected XMLEventFactory initialValue() { |
|
48 |
return XMLEventFactory.newInstance(); |
|
49 |
} |
|
50 |
}; |
|
51 |
|
|
52 |
public static final String UTF_8 = "UTF-8"; |
|
53 |
|
|
54 |
final XMLEventReader parser; |
|
55 |
|
|
56 |
private XMLEvent current = null; |
|
57 |
|
|
58 |
private String element; |
|
59 |
|
|
60 |
private InputStream inputStream; |
|
61 |
|
|
62 |
public XMLIterator(final String element, final InputStream inputStream) { |
|
63 |
super(); |
|
64 |
this.element = element; |
|
65 |
this.inputStream = inputStream; |
|
66 |
this.parser = getParser(); |
|
67 |
try { |
|
68 |
this.current = findElement(parser); |
|
69 |
} catch (XMLStreamException e) { |
|
70 |
log.warn("cannot init parser position. No element found: " + element); |
|
71 |
current = null; |
|
72 |
} |
|
73 |
} |
|
74 |
|
|
75 |
@Override |
|
76 |
public boolean hasNext() { |
|
77 |
return current != null; |
|
78 |
} |
|
79 |
|
|
80 |
@Override |
|
81 |
public String next() { |
|
82 |
String result = null; |
|
83 |
try { |
|
84 |
result = copy(parser); |
|
85 |
current = findElement(parser); |
|
86 |
return result; |
|
87 |
} catch (XMLStreamException e) { |
|
88 |
throw new RuntimeException(String.format("error copying xml, built so far: '%s'", result), e); |
|
89 |
} |
|
90 |
} |
|
91 |
|
|
92 |
@Override |
|
93 |
public void remove() { |
|
94 |
throw new UnsupportedOperationException(); |
|
95 |
} |
|
96 |
|
|
97 |
@SuppressWarnings("finally") |
|
98 |
private String copy(final XMLEventReader parser) throws XMLStreamException { |
|
99 |
final StringWriter result = new StringWriter(); |
|
100 |
try { |
|
101 |
final XMLEventWriter writer = outputFactory.get().createXMLEventWriter(result); |
|
102 |
final StartElement start = current.asStartElement(); |
|
103 |
final StartElement newRecord = eventFactory.get().createStartElement(start.getName(), start.getAttributes(), start.getNamespaces()); |
|
104 |
|
|
105 |
// new root record |
|
106 |
writer.add(newRecord); |
|
107 |
|
|
108 |
// copy the rest as it is |
|
109 |
while (parser.hasNext()) { |
|
110 |
final XMLEvent event = parser.nextEvent(); |
|
111 |
|
|
112 |
// TODO: replace with depth tracking instead of close tag tracking. |
|
113 |
if (event.isEndElement() && event.asEndElement().getName().getLocalPart().equals(element)) { |
|
114 |
writer.add(event); |
|
115 |
break; |
|
116 |
} |
|
117 |
|
|
118 |
writer.add(event); |
|
119 |
} |
|
120 |
writer.close(); |
|
121 |
} finally { |
|
122 |
return result.toString(); |
|
123 |
} |
|
124 |
} |
|
125 |
|
|
126 |
/** |
|
127 |
* Looks for the next occurrence of the splitter element. |
|
128 |
* |
|
129 |
* @param parser |
|
130 |
* @return |
|
131 |
* @throws XMLStreamException |
|
132 |
*/ |
|
133 |
private XMLEvent findElement(final XMLEventReader parser) throws XMLStreamException { |
|
134 |
|
|
135 |
/* |
|
136 |
* if (current != null && element.equals(current.asStartElement().getName().getLocalPart())) { return current; } |
|
137 |
*/ |
|
138 |
|
|
139 |
XMLEvent peek = parser.peek(); |
|
140 |
if (peek != null && peek.isStartElement()) { |
|
141 |
String name = peek.asStartElement().getName().getLocalPart(); |
|
142 |
if (element.equals(name)) { return peek; } |
|
143 |
} |
|
144 |
|
|
145 |
while (parser.hasNext()) { |
|
146 |
final XMLEvent event = parser.nextEvent(); |
|
147 |
if (event != null && event.isStartElement()) { |
|
148 |
String name = event.asStartElement().getName().getLocalPart(); |
|
149 |
if (element.equals(name)) { return event; } |
|
150 |
} |
|
151 |
} |
|
152 |
return null; |
|
153 |
} |
|
154 |
|
|
155 |
private XMLEventReader getParser() { |
|
156 |
try { |
|
157 |
return inputFactory.get().createXMLEventReader(sanitize(inputStream)); |
|
158 |
} catch (XMLStreamException e) { |
|
159 |
throw new RuntimeException(e); |
|
160 |
} |
|
161 |
} |
|
162 |
|
|
163 |
private Reader sanitize(final InputStream in) { |
|
164 |
final CharsetDecoder charsetDecoder = Charset.forName(UTF_8).newDecoder(); |
|
165 |
charsetDecoder.onMalformedInput(CodingErrorAction.REPLACE); |
|
166 |
charsetDecoder.onUnmappableCharacter(CodingErrorAction.REPLACE); |
|
167 |
return new InputStreamReader(in, charsetDecoder); |
|
168 |
} |
|
169 |
|
|
170 |
} |
modules/cnr-misc-utils/tags/cnr-misc-utils-1.0.4/src/main/java/eu/dnetlib/miscutils/iterators/IterableIterator.java | ||
---|---|---|
1 |
package eu.dnetlib.miscutils.iterators; |
|
2 |
|
|
3 |
import java.util.Iterator; |
|
4 |
|
|
5 |
/** |
|
6 |
* Useful if you want to quickly iterate an iterable with the new java 5 syntax. |
|
7 |
* |
|
8 |
* @author marko |
|
9 |
* |
|
10 |
* @param <T> |
|
11 |
*/ |
|
12 |
public class IterableIterator<T> implements Iterable<T> { |
|
13 |
private Iterator<T> iter; |
|
14 |
|
|
15 |
public IterableIterator(Iterator<T> iter) { |
|
16 |
this.iter = iter; |
|
17 |
} |
|
18 |
|
|
19 |
@Override |
|
20 |
public Iterator<T> iterator() { |
|
21 |
return iter; |
|
22 |
} |
|
23 |
} |
|
24 |
|
modules/cnr-misc-utils/tags/cnr-misc-utils-1.0.4/src/main/java/eu/dnetlib/miscutils/iterators/IterablePair.java | ||
---|---|---|
1 |
package eu.dnetlib.miscutils.iterators; |
|
2 |
|
|
3 |
import java.util.Iterator; |
|
4 |
import java.util.List; |
|
5 |
|
|
6 |
import eu.dnetlib.miscutils.collections.Pair; |
|
7 |
|
|
8 |
public class IterablePair <A, B> implements Iterable<Pair<A, B>> { |
|
9 |
private final List<A> first; |
|
10 |
private final List<B> second; |
|
11 |
|
|
12 |
public IterablePair(List<A> first, List<B> second) { |
|
13 |
this.first = first; |
|
14 |
this.second = second; |
|
15 |
} |
|
16 |
|
|
17 |
@Override |
|
18 |
public Iterator<Pair<A, B>> iterator() { |
|
19 |
return new ParallelIterator<A, B>(first.iterator(), second.iterator()); |
|
20 |
} |
|
21 |
} |
Also available in: Unified diff
cleanup