- Serialiser bug with custom objects and string inside another custom object fixed
- Bridge default maxPrintSize parameter fixed
- Progress/ProgressBar synchronisation issues fixed
# nikiroo-utils
+## Version 3.1.6
+
+- Fix Serialiser issue with custom objects and String in a custom object
+- Fix Progress/ProgressBar synchronisation issues
+- Fix Bridge default maxPrintSize parameter
+
## Version 3.1.5
- Fix Cache with no-parent file
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.Set;
/**
* Progress reporting system, possibly nested.
*
* @return the children (Who will think of the children??)
*/
- public Set<Progress> getChildren() {
- return children.keySet();
+ public List<Progress> getChildren() {
+ synchronized (getLock()) {
+ return new ArrayList<Progress>(children.keySet());
+ }
}
/**
* the listener
*/
public void addProgressListener(ProgressListener l) {
- this.listeners.add(l);
+ synchronized (getLock()) {
+ this.listeners.add(l);
+ }
}
/**
* @return TRUE if it was found (and removed)
*/
public boolean removeProgressListener(ProgressListener l) {
- return this.listeners.remove(l);
+ synchronized (getLock()) {
+ return this.listeners.remove(l);
+ }
}
/**
public void progress(Progress pg, String name) {
synchronized (getLock()) {
double total = relativeLocalProgress;
- for (Entry<Progress, Double> entry : children.entrySet()) {
- total += (entry.getValue() / (max - min))
- * entry.getKey().getRelativeProgress();
+ synchronized (getLock()) {
+ for (Entry<Progress, Double> entry : children
+ .entrySet()) {
+ total += (entry.getValue() / (max - min))
+ * entry.getKey().getRelativeProgress();
+ }
}
setRelativeProgress(pg, name, total);
}
});
- this.children.put(progress, weight);
+ synchronized (getLock()) {
+ this.children.put(progress, weight);
+ }
}
/**
public boolean encode(StringBuilder builder, Object value) {
int prev = builder.length();
String customString = toString(value);
- builder.append("custom:").append(getType()).append(":");
+ builder.append("custom^").append(getType()).append("^");
if (!SerialUtils.encode(builder, customString)) {
builder.delete(prev, builder.length());
return false;
}
public static boolean isCustom(String encodedValue) {
- int pos1 = encodedValue.indexOf(':');
- int pos2 = encodedValue.indexOf(':', pos1 + 1);
+ int pos1 = encodedValue.indexOf('^');
+ int pos2 = encodedValue.indexOf('^', pos1 + 1);
- return pos1 >= 0 && pos2 >= 0 && encodedValue.startsWith("custom:");
+ return pos1 >= 0 && pos2 >= 0 && encodedValue.startsWith("custom^");
}
public static String typeOf(String encodedValue) {
- int pos1 = encodedValue.indexOf(':');
- int pos2 = encodedValue.indexOf(':', pos1 + 1);
+ int pos1 = encodedValue.indexOf('^');
+ int pos2 = encodedValue.indexOf('^', pos1 + 1);
String type = encodedValue.substring(pos1 + 1, pos2);
return type;
}
public static String contentOf(String encodedValue) {
- int pos1 = encodedValue.indexOf(':');
- int pos2 = encodedValue.indexOf(':', pos1 + 1);
+ int pos1 = encodedValue.indexOf('^');
+ int pos2 = encodedValue.indexOf('^', pos1 + 1);
String encodedContent = encodedValue.substring(pos2 + 1);
return encodedContent;
if (line.endsWith(":")) {
// field value is compound
currentFieldName = line.substring(0, line.length() - 1);
- } else if (line.startsWith(":") || !line.contains(":")) {
+ } else if (line.startsWith(":") || !line.contains(":")
+ || line.startsWith("\"") || CustomSerializer.isCustom(line)) {
// not a field value but a direct value
me = SerialUtils.decode(line);
} else {
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.UnknownFormatConversionException;
* <li>Enum (any enum whose name and value is known by the caller)</li>
* <li>java.awt.image.BufferedImage (as a {@link CustomSerializer})</li>
* <li>An array of the above (as a {@link CustomSerializer})</li>
+ * <li>URL</li>
* </ul>
*
* @author niki
}
});
+ // URL:
+ customTypes.put("java.net.URL", new CustomSerializer() {
+ @Override
+ protected String toString(Object value) {
+ if (value != null) {
+ return ((URL) value).toString();
+ }
+ return null;
+ }
+
+ @Override
+ protected Object fromString(String content) throws IOException {
+ if (content != null) {
+ return new URL(content);
+ }
+ return null;
+ }
+
+ @Override
+ protected String getType() {
+ return "java.net.URL";
+ }
+ });
+
// Images (this is currently the only supported image type by default)
customTypes.put("java.awt.image.BufferedImage", new CustomSerializer() {
@Override
import java.io.IOException;
import java.net.Socket;
+import java.net.UnknownHostException;
import be.nikiroo.utils.Version;
* TRUE for an SSL connection, FALSE for plain text
*
* @throws IOException
- * in case of I/O error when creating the socket
+ * in case of I/O error
+ * @throws UnknownHostException
+ * if the host is not known
+ * @throws IllegalArgumentException
+ * if the port parameter is outside the specified range of valid
+ * port values, which is between 0 and 65535, inclusive
*/
public ConnectActionClient(String host, int port, boolean ssl)
throws IOException {
* the client version
*
* @throws IOException
- * in case of I/O error when creating the socket
+ * in case of I/O error
+ * @throws UnknownHostException
+ * if the host is not known
+ * @throws IllegalArgumentException
+ * if the port parameter is outside the specified range of valid
+ * port values, which is between 0 and 65535, inclusive
*/
public ConnectActionClient(String host, int port, boolean ssl,
Version version) throws IOException {
import java.io.IOException;
import java.net.Socket;
+import java.net.UnknownHostException;
import be.nikiroo.utils.Version;
* TRUE for an SSL connection, FALSE for plain text
*
* @throws IOException
- * in case of I/O error when creating the socket
+ * in case of I/O error
+ * @throws UnknownHostException
+ * if the IP address of the host could not be determined
+ * @throws IllegalArgumentException
+ * if the port parameter is outside the specified range of valid
+ * port values, which is between 0 and 65535, inclusive
*/
public ConnectActionClientObject(String host, int port, boolean ssl)
throws IOException {
* the client version
*
* @throws IOException
- * in case of I/O error when creating the socket
+ * in case of I/O error
+ * @throws UnknownHostException
+ * if the IP address of the host could not be determined
+ * @throws IllegalArgumentException
+ * if the port parameter is outside the specified range of valid
+ * port values, which is between 0 and 65535, inclusive
*/
public ConnectActionClientObject(String host, int port, boolean ssl,
Version version) throws IOException {
import java.io.IOException;
import java.net.Socket;
+import java.net.UnknownHostException;
import be.nikiroo.utils.Version;
* TRUE for an SSL connection, FALSE for plain text
*
* @throws IOException
- * in case of I/O error when creating the socket
+ * in case of I/O error
+ * @throws UnknownHostException
+ * if the IP address of the host could not be determined
+ * @throws IllegalArgumentException
+ * if the port parameter is outside the specified range of valid
+ * port values, which is between 0 and 65535, inclusive
*/
public ConnectActionClientString(String host, int port, boolean ssl)
throws IOException {
* the client version
*
* @throws IOException
- * in case of I/O error when creating the socket
+ * in case of I/O error
+ * @throws UnknownHostException
+ * if the IP address of the host could not be determined
+ * @throws IllegalArgumentException
+ * if the port parameter is outside the specified range of valid
+ * port values, which is between 0 and 65535, inclusive
*/
public ConnectActionClientString(String host, int port, boolean ssl,
Version version) throws IOException {
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
+import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
*
* @throws IOException
* in case of I/O error
+ * @throws UnknownHostException
+ * if the IP address of the host could not be determined
+ * @throws IllegalArgumentException
+ * if the port parameter is outside the specified range of valid
+ * port values, which is between 0 and 65535, inclusive
*/
public Server(int port, boolean ssl) throws IOException {
this((String) null, port, ssl);
*
* @throws IOException
* in case of I/O error
+ * @throws UnknownHostException
+ * if the IP address of the host could not be determined
+ * @throws IllegalArgumentException
+ * if the port parameter is outside the specified range of valid
+ * port values, which is between 0 and 65535, inclusive
*/
public Server(String name, int port, boolean ssl) throws IOException {
this.name = name;
}
try {
- tracer.trace(name + ": server starting on port " + port);
+ tracer.trace(name + ": server starting on port " + port + " ("
+ + (ssl ? "SSL" : "plain text") + ")");
while (started && !exiting) {
count(1);
*
* @throws IOException
* in case of I/O error
+ * @throws UnknownHostException
+ * if the host is not known
+ * @throws IllegalArgumentException
+ * if the port parameter is outside the specified range of valid
+ * port values, which is between 0 and 65535, inclusive
*/
static Socket createSocket(String host, int port, boolean ssl)
throws IOException {
*
* @throws IOException
* in case of I/O error
+ * @throws UnknownHostException
+ * if the IP address of the host could not be determined
+ * @throws IllegalArgumentException
+ * if the port parameter is outside the specified range of valid
+ * port values, which is between 0 and 65535, inclusive
*/
static ServerSocket createSocketServer(int port, boolean ssl)
throws IOException {
import java.io.IOException;
import java.lang.reflect.Array;
import java.net.Socket;
+import java.net.UnknownHostException;
import be.nikiroo.utils.StringUtils;
import be.nikiroo.utils.TraceHandler;
*
* @throws IOException
* in case of I/O error
+ * @throws UnknownHostException
+ * if the IP address of the host could not be determined
+ * @throws IllegalArgumentException
+ * if the port parameter is outside the specified range of valid
+ * port values, which is between 0 and 65535, inclusive
*/
public ServerBridge(int port, boolean ssl, String forwardToHost,
int forwardToPort, boolean forwardToSsl) throws IOException {
*
* @throws IOException
* in case of I/O error
+ * @throws UnknownHostException
+ * if the IP address of the host could not be determined
+ * @throws IllegalArgumentException
+ * if the port parameter is outside the specified range of valid
+ * port values, which is between 0 and 65535, inclusive
*/
public ServerBridge(String name, int port, boolean ssl,
String forwardToHost, int forwardToPort, boolean forwardToSsl)
onClientContact(clientVersion);
final ConnectActionServerString bridge = this;
- new ConnectActionClientString(forwardToHost, forwardToPort,
- forwardToSsl, clientVersion) {
- @Override
- public void action(final Version serverVersion)
- throws Exception {
- onServerContact(serverVersion);
+ try {
+ new ConnectActionClientString(forwardToHost, forwardToPort,
+ forwardToSsl, clientVersion) {
+ @Override
+ public void action(final Version serverVersion)
+ throws Exception {
+ onServerContact(serverVersion);
- for (String fromClient = bridge.rec(); fromClient != null; fromClient = bridge
- .rec()) {
- onRec(clientVersion, fromClient);
- String fromServer = send(fromClient);
- onSend(serverVersion, fromServer);
- bridge.send(fromServer);
- }
+ for (String fromClient = bridge.rec(); fromClient != null; fromClient = bridge
+ .rec()) {
+ onRec(clientVersion, fromClient);
+ String fromServer = send(fromClient);
+ onSend(serverVersion, fromServer);
+ bridge.send(fromServer);
+ }
- getTraceHandler().trace("=== DONE", 1);
- getTraceHandler().trace("", 1);
- }
+ getTraceHandler().trace("=== DONE", 1);
+ getTraceHandler().trace("", 1);
+ }
- @Override
- protected void onError(Exception e) {
- ServerBridge.this.onError(e);
- }
- }.connect();
+ @Override
+ protected void onError(Exception e) {
+ ServerBridge.this.onError(e);
+ }
+ }.connect();
+ } catch (Exception e) {
+ ServerBridge.this.onError(e);
+ }
}
};
}
trace("<<< SERVER (" + serverVersion + ")", data);
}
+ @Override
+ public void run() {
+ getTraceHandler().trace(
+ getName() + ": will forward to " + forwardToHost + ":"
+ + forwardToPort + " ("
+ + (forwardToSsl ? "SSL" : "plain text") + ")");
+ super.run();
+ }
+
/**
* Trace the data with the given prefix.
*
if (args.length > 6) {
traceLevel = Integer.parseInt(args[i++]);
}
- int maxPrintSize = 1;
+ int maxPrintSize = 0;
if (args.length > 7) {
maxPrintSize = Integer.parseInt(args[i++]);
}
import java.io.IOException;
import java.net.Socket;
+import java.net.UnknownHostException;
import be.nikiroo.utils.Version;
*
* @throws IOException
* in case of I/O error
+ * @throws UnknownHostException
+ * if the IP address of the host could not be determined
+ * @throws IllegalArgumentException
+ * if the port parameter is outside the specified range of valid
+ * port values, which is between 0 and 65535, inclusive
*/
public ServerObject(int port, boolean ssl) throws IOException {
super(port, ssl);
*
* @throws IOException
* in case of I/O error
+ * @throws UnknownHostException
+ * if the IP address of the host could not be determined
+ * @throws IllegalArgumentException
+ * if the port parameter is outside the specified range of valid
+ * port values, which is between 0 and 65535, inclusive
*/
public ServerObject(String name, int port, boolean ssl) throws IOException {
super(name, port, ssl);
import java.io.IOException;
import java.net.Socket;
+import java.net.UnknownHostException;
import be.nikiroo.utils.Version;
*
* @throws IOException
* in case of I/O error
+ * @throws UnknownHostException
+ * if the IP address of the host could not be determined
+ * @throws IllegalArgumentException
+ * if the port parameter is outside the specified range of valid
+ * port values, which is between 0 and 65535, inclusive
*/
public ServerString(int port, boolean ssl) throws IOException {
super(port, ssl);
*
* @throws IOException
* in case of I/O error
+ * @throws UnknownHostException
+ * if the IP address of the host could not be determined
+ * @throws IllegalArgumentException
+ * if the port parameter is outside the specified range of valid
+ * port values, which is between 0 and 65535, inclusive
*/
public ServerString(String name, int port, boolean ssl) throws IOException {
super(name, port, ssl);
package be.nikiroo.utils.test;
+import java.net.URL;
+
import be.nikiroo.utils.Version;
import be.nikiroo.utils.serial.server.ConnectActionClientObject;
import be.nikiroo.utils.serial.server.ConnectActionClientString;
ServerBridge br = null;
if (bridge) {
br = new ServerBridge(0, ssl, "", port, ssl);
+ br.setTraceHandler(null);
port = br.getPort();
assertEquals(
@Override
protected void onError(Exception e) {
- super.onError(e);
err[0] = e;
}
};
ServerBridge br = null;
if (bridge) {
br = new ServerBridge(0, ssl, "", port, ssl);
+ br.setTraceHandler(null);
port = br.getPort();
br.start();
}
@Override
protected void onError(Exception e) {
- super.onError(e);
err[0] = e;
}
};
ServerBridge br = null;
if (bridge) {
br = new ServerBridge(0, ssl, "", port, ssl);
+ br.setTraceHandler(null);
port = br.getPort();
br.start();
}
@Override
protected void onError(Exception e) {
- super.onError(e);
err[0] = e;
}
};
ServerBridge br = null;
if (bridge) {
br = new ServerBridge(0, ssl, "", port, ssl);
+ br.setTraceHandler(null);
port = br.getPort();
br.start();
}
ServerBridge br = null;
if (bridge) {
- br = new ServerBridge(0, ssl, "", port, ssl) {
- @Override
- protected void onError(Exception e) {
- }
- };
+ br = new ServerBridge(0, ssl, "", port, ssl);
+ br.setTraceHandler(null);
port = br.getPort();
br.start();
}
@Override
protected void onError(Exception e) {
- super.onError(e);
err[0] = e;
}
};
ServerBridge br = null;
if (bridge) {
br = new ServerBridge(0, ssl, "", port, ssl);
+ br.setTraceHandler(null);
port = br.getPort();
br.start();
}
@Override
protected void onError(Exception e) {
- super.onError(e);
err[0] = e;
}
};
ServerBridge br = null;
if (bridge) {
br = new ServerBridge(0, ssl, "", port, ssl);
+ br.setTraceHandler(null);
port = br.getPort();
br.start();
}
}
});
+ series.addTest(new TestCase("Object array of URLs " + ssls) {
+ final Object[] sent = new Object[1];
+ final Object[] recd = new Object[1];
+ final Exception[] err = new Exception[1];
+
+ @Override
+ public void test() throws Exception {
+ ServerObject server = new ServerObject(this.getName(), 0, ssl) {
+ @Override
+ protected Object onRequest(
+ ConnectActionServerObject action,
+ Version clientVersion, Object data)
+ throws Exception {
+ sent[0] = data;
+ return new Object[] { "ACK" };
+ }
+
+ @Override
+ protected void onError(Exception e) {
+ err[0] = e;
+ }
+ };
+
+ int port = server.getPort();
+
+ server.start();
+
+ ServerBridge br = null;
+ if (bridge) {
+ br = new ServerBridge(0, ssl, "", port, ssl);
+ br.setTraceHandler(null);
+ port = br.getPort();
+ br.start();
+ }
+
+ try {
+ try {
+ new ConnectActionClientObject(null, port, ssl) {
+ @Override
+ public void action(Version serverVersion)
+ throws Exception {
+ recd[0] = send(new Object[] {
+ "key",
+ new URL(
+ "https://example.com/from_client"),
+ "https://example.com/from_client" });
+ }
+ }.connect();
+ } finally {
+ server.stop();
+ }
+ } finally {
+ if (br != null) {
+ br.stop();
+ }
+ }
+
+ if (err[0] != null) {
+ fail("An exception was thrown: " + err[0].getMessage());
+ }
+
+ Object[] sento = (Object[]) (sent[0]);
+ Object[] recdo = (Object[]) (recd[0]);
+
+ assertEquals("key", sento[0]);
+ assertEquals("https://example.com/from_client",
+ ((URL) sento[1]).toString());
+ assertEquals("https://example.com/from_client", sento[2]);
+ assertEquals("ACK", recdo[0]);
+ }
+ });
+
series.addTest(new TestCase("Multiple call from client " + ssls) {
final Object[] sent = new Object[3];
final Object[] recd = new Object[3];
@Override
protected void onError(Exception e) {
- super.onError(e);
err[0] = e;
}
};
ServerBridge br = null;
if (bridge) {
br = new ServerBridge(0, ssl, "", port, ssl);
+ br.setTraceHandler(null);
port = br.getPort();
br.start();
}
package be.nikiroo.utils.test;
+import java.net.URL;
+
import be.nikiroo.utils.serial.Exporter;
import be.nikiroo.utils.serial.Importer;
}
});
+ addTest(new TestCase("URL Import/Export") {
+ @Override
+ public void test() throws Exception {
+ URL data = new URL("https://fanfan.be/");
+ String encoded = new Exporter().append(data).toString(false);
+ Object redata = new Importer().read(encoded).getValue();
+ String reencoded = new Exporter().append(redata)
+ .toString(false);
+
+ assertEquals(encoded.replaceAll("@[0-9]*", "@REF"),
+ reencoded.replaceAll("@[0-9]*", "@REF"));
+ }
+ });
+
+ addTest(new TestCase("URL-String Import/Export") {
+ @Override
+ public void test() throws Exception {
+ String data = new URL("https://fanfan.be/").toString();
+ String encoded = new Exporter().append(data).toString(false);
+ Object redata = new Importer().read(encoded).getValue();
+ String reencoded = new Exporter().append(redata)
+ .toString(false);
+
+ assertEquals(encoded.replaceAll("@[0-9]*", "@REF"),
+ reencoded.replaceAll("@[0-9]*", "@REF"));
+ assertEquals(data, redata);
+ }
+ });
+
+ addTest(new TestCase("URL/URL-String arrays Import/Export") {
+ @Override
+ public void test() throws Exception {
+ final String url = "https://fanfan.be/";
+
+ Object[] data = new Object[] { new URL(url), url };
+ String encoded = new Exporter().append(data).toString(false);
+ Object redata = new Importer().read(encoded).getValue();
+ String reencoded = new Exporter().append(redata)
+ .toString(false);
+
+ assertEquals(encoded.replaceAll("@[0-9]*", "@REF"),
+ reencoded.replaceAll("@[0-9]*", "@REF"));
+ assertEquals(data[0], ((Object[]) redata)[0]);
+ assertEquals(data[1], ((Object[]) redata)[1]);
+ }
+ });
+
addTest(new TestCase("Import/Export with nested objects") {
@Override
public void test() throws Exception {
private List<ActionListener> actionListeners;
private List<ActionListener> updateListeners;
private Progress pg;
+ private Object lock = new Object();
public ProgressBar() {
bars = new HashMap<Progress, JProgressBar>();
bar.setValue(pg.getProgress());
bar.setString(pg.getName());
+ synchronized (lock) {
for (Progress pgChild : getChildrenAsOrderedList(pg)) {
JProgressBar barChild = bars
.get(pgChild);
barChild.setValue(pgChild.getProgress());
barChild.setString(pgChild.getName());
}
-
+
if (ProgressBar.this.pg == null) {
bars.clear();
} else {
bars = newBars;
-
+ }
+ }
+
+ if (ProgressBar.this.pg != null) {
if (pg.isDone()) {
pg.removeProgressListener(l);
for (ActionListener listener : actionListeners) {
// only named ones
private List<Progress> getChildrenAsOrderedList(Progress pg) {
List<Progress> children = new ArrayList<Progress>();
- for (Progress child : pg.getChildren()) {
+
+ synchronized (lock) {
+ for (Progress child : pg.getChildren()) {
if (child.getName() != null && !child.getName().isEmpty()) {
children.add(child);
}
children.addAll(getChildrenAsOrderedList(child));
}
-
+ }
+
return children;
}
private void update() {
- invalidate();
- removeAll();
-
- if (pg != null) {
- setLayout(new GridLayout(bars.size(), 1));
- add(bars.get(pg), 0);
- for (Progress child : getChildrenAsOrderedList(pg)) {
- JProgressBar jbar = bars.get(child);
- if (jbar != null) {
- add(jbar);
+ synchronized (lock) {
+ invalidate();
+ removeAll();
+
+ if (pg != null) {
+ setLayout(new GridLayout(bars.size(), 1));
+ add(bars.get(pg), 0);
+ for (Progress child : getChildrenAsOrderedList(pg)) {
+ JProgressBar jbar = bars.get(child);
+ if (jbar != null) {
+ add(jbar);
+ }
}
}
- }
- validate();
- repaint();
+ validate();
+ repaint();
+ }
for (ActionListener listener : updateListeners) {
listener.actionPerformed(new ActionEvent(this, 0, "update"));