Commit 83bf257b authored by Eric Tobias's avatar Eric Tobias

Bootstrapping and library updates.

This commit constitutes the first nightly bootstrapping build. As of now, bootstrapping supports most coronas but no InformationProvides. Only the BaseWidget is supported at the moment.

+ String Externalization for to make changes regarding the boostrapping XML maintainable.
+ Updated some libraries such as Guava and JDOM2 (see Changelog)
+ Added constructors to most base builders of the coronas and the base widget to work with a provided JDOM2 Element node.
+ Added bootstrapping classes with static methods to provide support to bootstrap other major classes such as concrete NetworkArapter implementations.
parent b580cbde
2.2.0
Implementation of XML based bootstrapping for widgets and coronas.
+ Moved to Guava 19
+ Moved to JDOM2 2.0.6
+ Added org.eclipse.osgi in version 3.7.1 to manage string internationalization (licensed as EPL 1)
+ Image and its related builders, notably those for the image-based corona, no longer throw a BuildException. This was already the case but the signature still contained the exception being thrown.
+ Removed the field method to set "alwaysActive" for coronas from the CoronaBuilder. The concept was removed as it is thought that coronas should not be always active.
+ Removed field and methods for corona persistence from Corona and the CoronaBuilder. No scenario exists that accounts for persistence and the related methods when drawing were not supported either.
+ Removed the field "background" and all related methods from Corona. Adjusted Image accordingly. The field was not used. Conceptually, coronas should never be part of the background.
2.1.4
+ Added test method for various classes.
......
......@@ -10,13 +10,15 @@ History
TULIP was designed and implemented in an iterative process as of 2014. The bulk of the framework has been developed by @etobias with the help of and under the watchful eyes of @vmaquil who heads the research activities in the Natural User Interfaces domain. From January to June 2014 the framework saw the first major developments with some complementary implementation and bug fixing activity done during the Summer and Fall of 2014. In Fall 2014, @yrangoni added the first traces of a lightweight logging library.
In January 2015 the project was migrated to Git, using GitLab as a platform.
Current development
We currently develop an adapter for the computer vision framework and are in the stages of testing it. Similarly, we are developing adapters to address networked devices.
We are currently developping a boostrapping mechanism that will allow to instantiate widgets and their coronas from an XML file. This development is part of the Re-Engage project.
Libraries and Licenses
As of now, the provided sources are still in development.
Currently the project depends on an in-house annotation library that is distributed with this project as well as Guava (licensed under Apache 2.0), JDOM (licensed under an Apache-style open source license), and the TUIO Java client (licensed as LGPL).
Currently the project depends on an in-house annotation library that is distributed with this project as well as Guava (licensed under Apache 2.0), JDOM2 (licensed under an Apache-style open source license), and the TUIO Java client (licensed as LGPL). The project uses the Eclipse OSGI Utility library (licensed as EPL1) for string externalization.
The network adapters are using BlueCove (licensed under Apache 2.0) for Bluetooth communication and RXTX (licensed as LGPL) for Xbee communication.
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<tangibles>
<objects>
<object>
<type>BaseWidget</type>
<coronas>
<corona>
<type>Shadow</type>
<centre>
<x>0</x>
<y>0</y>
<z>0</z>
</centre>
</corona>
</coronas>
<name>Marty</name>
<definingShape>Circle</definingShape>
<networkAdapter></networkAdapter>
</object>
</objects>
<cursors>
<cursor>
<type></type>
<coronas>
<corona></corona>
</coronas>
<name></name>
<defining-shape></defining-shape>
<network-adapter></network-adapter>
</cursor>
</cursors>
<blobs>
<blob>
<type></type>
<coronas>
<corona></corona>
</coronas>
<name></name>
<defining-shape></defining-shape>
<network-adapter></network-adapter>
</blob>
</blobs>
</tangibles>
<!-- Font: http://docs.oracle.com/javase/1.5.0/docs/api/java/awt/Font.html#decode%28java.lang.String%29 -->
ALPHA=alpha
BACKGROUND_COLOUR=backgroundColour
BORDER_THICKNESS=borderThickness
BORDER_WIDTH=borderWidth
CENTRE_NODE=centre
CENTRED=centred
COLOUR=colour
CORONAS_NODE=coronas
DEFINING_SHAPE_NODE=definingShape
DRAW_BORDER=drawBorder
DRAW_PRIORITY_NODE=drawPriority
EDGE_COLOUR=edgeColour
FILL_COLOUR=fillColour
FONT=font
FONT_SIZE=fontSize
HANDLE_NODE=handle
HANDLES_NODE=handles
IMAGE=image
INFORMATION=information
INITIAL_ROTATION_NODE=initialRotation
INITIAL_TRANSLATION_NODE=initialTranslation
JAVA_AWT_COLOR_NAMESPACE=java.awt.Color
LENGTH=length
LINE=line
LINE_HEIGHT_RATIO=lineHeightRatio
LINE_WIDTH=lineWidth
NAME_NODE=name
NETWORK_ADAPTER_NODE=networkAdapter
RADIUS=radius
ROTATE_WITH_HANDLE_NODE=rotateWithHandle
SHAPE_NODE=shape
SPIN_ON_CORONA_CENTRE_NODE=spinOnCoronaCentre
START=start
TEXT=text
<?xml version="1.0" encoding="UTF-8"?>
<tangibles>
<objects>
<object>
<type>BaseWidget</type>
<handles>
<handle>1</handle>
</handles>
<coronas>
<corona>
<type>Shadow</type>
<handle>1</handle>
<centre>
<x>0</x>
<y>0</y>
<z>0</z>
</centre>
</corona>
</coronas>
<name>Marty</name>
<definingShape>Circle</definingShape>
<networkAdapter></networkAdapter>
</object>
</objects>
<cursors>
<cursor>
<type></type>
<coronas>
<corona></corona>
</coronas>
<name></name>
<defining-shape></defining-shape>
<network-adapter></network-adapter>
</cursor>
</cursors>
<blobs>
<blob>
<type></type>
<coronas>
<corona></corona>
</coronas>
<name></name>
<defining-shape></defining-shape>
<network-adapter></network-adapter>
</blob>
</blobs>
</tangibles>
......@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>lu.list.itis.dkd.tui</groupId>
<artifactId>tulip</artifactId>
<version>2.0.41</version>
<version>2.2.0</version>
<name>TULIP</name>
<description>A framework for tabletop tangible user interface applications.</description>
<build>
......@@ -23,12 +23,12 @@
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom2</artifactId>
<version>2.0.5</version>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>15.0</version>
<version>19.0</version>
</dependency>
<dependency>
<groupId>net.sf.bluecove</groupId>
......@@ -40,7 +40,6 @@
<artifactId>rxtx</artifactId>
<version>2.1.7</version>
</dependency>
<dependency>
<groupId>net.sourceforge.tuio</groupId>
<artifactId>tuio</artifactId>
......@@ -51,5 +50,10 @@
<artifactId>dbc-annotation</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.eclipse.osgi</groupId>
<artifactId>org.eclipse.osgi</artifactId>
<version>3.7.1</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
......@@ -47,7 +47,7 @@ import javax.swing.JFrame;
* Class managing the setup of the window displaying all top-level TUI related visualisation as well
* as any configuration behaviour.
*
* @author Eric TOBIAS [eric.tobias@list.lu]
* @author Eric Tobias [eric.tobias@list.lu]
* @since 1.0
* @version 1.0.2
*/
......@@ -113,8 +113,9 @@ public class TangibleInterfaceManager extends JComponent {
title = interfaceProperties.getProperty("frameTitle", "TangibleApplication"); //$NON-NLS-1$ //$NON-NLS-2$
String calibration = interfaceProperties.getProperty("calibrationFileURI"); //$NON-NLS-1$
if (calibration != null)
if (calibration != null) {
calibrationFileURI = calibration;
}
device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
Calibration.loadFromFile(calibrationFileURI);
......
/**
* Copyright Luxembourg Institute of Science and Technology, 2015. All rights reserved.
*
* This file is part of TULIP.
*
* TULIP 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, version 3 of the
* License.
*
* TULIP 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 Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with TULIP. If
* not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*/
package lu.list.itis.dkd.tui.bootstrapping;
import lu.list.itis.dkd.tui.exception.BuildException;
import lu.list.itis.dkd.tui.widget.corona.Corona;
import lu.list.itis.dkd.tui.widget.corona.builder.CoronaBuilder;
import com.google.common.collect.Multimap;
import com.google.common.collect.TreeMultimap;
import org.jdom2.Element;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* @author Eric Tobias [eric.tobias@list.lu]
* @since 2.2
* @version 2.2.0
*/
public class CoronaBootstrapper {
private static final String CORONA_BUILDER_NAMESPACE = "lu.list.itis.dkd.tui.widget.corona.builder."; //$NON-NLS-1$
/**
* Method used to determine the appropriate builder for a given corona and then issue a build
* call.
*
* @param coronaNode
* The node from a larger document that contains, as children, all the necessary
* information to resolve the correct builder and build the final, concrete, corona.
* @return The final concrete corona as defined by the children of the element node.
* @throws ClassNotFoundException
* Thrown when the class of the builder for the corona could not be found.
* @throws SecurityException
* Thrown when the constructor cannot be retrieved due to some security constraints.
* @throws NoSuchMethodException
* Thrown when no constructor with the given parameter type is available.
* @throws InvocationTargetException
* Thrown if the invocation of any constructor through reflection throws an exception.
* @throws IllegalArgumentException
* Thrown when the provided argument is not eligible for the builder's constructor.
* @throws IllegalAccessException
* Thrown if this Constructor object is enforcing Java language access control and the
* underlying constructor is inaccessible.
* @throws InstantiationException
* Thrown if the class that declares the underlying constructor represents an abstract
* class.
*/
private static Corona getCorona(Element coronaNode) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
Element type = coronaNode.getChild("type"); //$NON-NLS-1$
Class<?> builder = Class.forName(CORONA_BUILDER_NAMESPACE + type.getValue() + "Builder"); //$NON-NLS-1$
@SuppressWarnings("unchecked")
Constructor<CoronaBuilder<?>> constructor = (Constructor<CoronaBuilder<?>>) builder.getConstructor(new Class[] {Element.class});
return constructor.newInstance(new Object[] {coronaNode}).build();
}
/**
* Method used for bootstrapping all coronas found as child nodes of a root node. The method
* will look for child nodes names <code>corona</code>.
*
* @param coronaRootNode
* The root node that holds all <code>corona</code> child nodes.
* @return A map containing all concrete {@link Corona} instances that could be build from the
* provided root node keyed to the handle ID to which they are associated. *
* @throws BuildException
* Thrown when a corona was not associated to any handle.
*/
public static Multimap<Integer, Corona> getCoronas(Element coronaRootNode) throws BuildException {
Multimap<Integer, Corona> coronas = TreeMultimap.create();
for (Element coronaNode : coronaRootNode.getChildren("corona")) { //$NON-NLS-1$
try {
int handleId = Integer.parseInt(coronaNode.getChildText("handle")); //$NON-NLS-1$
coronas.put(handleId, getCorona(coronaNode));
} catch (NumberFormatException nfe) {
throw new BuildException("The corona was not associated with any handle. The handle ID may not be null!", nfe); //$NON-NLS-1$
} catch (ReflectiveOperationException roe) {
throw new BuildException("One or more operations failed while issuing a reflective call!", roe); //$NON-NLS-1$
}
}
return coronas;
}
}
\ No newline at end of file
/**
* Copyright Luxembourg Institute of Science and Technology, 2015. All rights reserved.
*
* This file is part of TULIP.
*
* TULIP 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, version 3 of the
* License.
*
* TULIP 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 Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with TULIP. If
* not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*/
package lu.list.itis.dkd.tui.bootstrapping;
import org.eclipse.osgi.util.NLS;
/**
* Auto-generated class for string externalization to be used to bundle all node names.
*
* @author Eric Tobias [eric.tobias@list.lu]
* @since 2.2
* @version 2.2.0
*/
@SuppressWarnings("javadoc")
public class Messages extends NLS {
private static final String BUNDLE_NAME = "messages"; //$NON-NLS-1$
public static String ALPHA;
public static String BACKGROUND_COLOUR;
public static String BORDER_THICKNESS;
public static String BORDER_WIDTH;
public static String CENTRE_NODE;
public static String CENTRED;
public static String COLOUR;
public static String CORONAS_NODE;
public static String DEFINING_SHAPE_NODE;
public static String DRAW_BORDER;
public static String DRAW_PRIORITY_NODE;
public static String EDGE_COLOUR;
public static String FILL_COLOUR;
public static String FONT;
public static String FONT_SIZE;
public static String HANDLE_NODE;
public static String HANDLES_NODE;
public static String IMAGE;
public static String INFORMATION;
public static String INITIAL_ROTATION_NODE;
public static String INITIAL_TRANSLATION_NODE;
public static String JAVA_AWT_COLOR_NAMESPACE;
public static String LENGTH;
public static String LINE;
public static String LINE_HEIGHT_RATIO;
public static String LINE_WIDTH;
public static String NAME_NODE;
public static String NETWORK_ADAPTER_NODE;
public static String RADIUS;
public static String ROTATE_WITH_HANDLE_NODE;
public static String SHAPE_NODE;
public static String SPIN_ON_CORONA_CENTRE_NODE;
public static String START;
public static String TEXT;
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
}
private Messages() {}
}
\ No newline at end of file
/**
* Copyright Luxembourg Institute of Science and Technology, 2015. All rights reserved.
*
* This file is part of TULIP.
*
* TULIP 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, version 3 of the
* License.
*
* TULIP 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 Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with TULIP. If
* not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*/
package lu.list.itis.dkd.tui.bootstrapping;
import lu.list.itis.dkd.dbc.annotation.NonNullByDefault;
import lu.list.itis.dkd.dbc.annotation.Nullable;
import lu.list.itis.dkd.tui.exception.BuildException;
import lu.list.itis.dkd.tui.network.adapter.BluetoothClient;
import lu.list.itis.dkd.tui.network.adapter.BluetoothServer;
import lu.list.itis.dkd.tui.network.adapter.NetworkAdapter;
import lu.list.itis.dkd.tui.network.adapter.TcpClient;
import lu.list.itis.dkd.tui.network.adapter.TcpServer;
import lu.list.itis.dkd.tui.network.adapter.XbeeAdapter;
import com.google.common.base.Strings;
import org.jdom2.Element;
import java.io.IOException;
/**
* Simple bootstrapper for the network adapter.
*
* @author Eric Tobias [eric.tobias@list.lu]
* @since 2.2
* @version 2.2.0
*/
@NonNullByDefault
public class NetworkAdapterBootstrapper {
/**
* /** Method used to build a {@link NetworkAdapter} instance given an archetype. The method
* will delegate the construction of the adapter to the adapter class' constructor, checking
* that preconditions on available parameters are met by the XML.
*
* @param networkAdapterNode
* Element that may contain, as child nodes, the parameters required to successfully
* bootstrap the required network adapter. The node required a child node named "type"
* that holds the exact type of adapter to be initialized. For example: {@link TcpServer}
* or {@link BluetoothClient}. Supported adapters are concrete sub-classes of
* {@link NetworkAdapter}.
* @return A {@link NetworkAdapter} as specified by the archetype with its fields set by the
* information found in the XML. Will return <code>null</code> should parameter be null.
* @throws BuildException
* Thrown when no archetype could be associated with the provided archetype parameter or
* if one or more of the preconditions on required parameters are not met.
*/
public static @Nullable NetworkAdapter getNetworkAdapter(@Nullable Element networkAdapterNode) throws BuildException {
if (null == networkAdapterNode || Strings.isNullOrEmpty(networkAdapterNode.getText())) {
return null;
}
String archetype = networkAdapterNode.getChildText("type"); //$NON-NLS-1$
if (Strings.isNullOrEmpty(archetype)) {
throw new BuildException("The \"type\" node must bot be <i>null</i> or empty. It must conform to one of the supported network adapters. Please consult TULIP's documentation for a list of supported network adapters!"); //$NON-NLS-1$
}
switch (archetype.toLowerCase()) {
case "bluetoothclient": //$NON-NLS-1$
try {
return new BluetoothClient(networkAdapterNode.getChildText("serviceUuid")); //$NON-NLS-1$
} catch (NullPointerException | IllegalArgumentException e) {
throw new BuildException("The network adapter failed to be initialized. The adapter requires a non-null and well-formed UUID held by a node named \"serviceUuid\"!", e); //$NON-NLS-1$
}
case "tcpclient": //$NON-NLS-1$
try {
int port = Integer.parseInt(networkAdapterNode.getChildText("port")); //$NON-NLS-1$
return new TcpClient(networkAdapterNode.getChildText("host"), port); //$NON-NLS-1$
} catch (NumberFormatException | IllegalStateException e) {
throw new BuildException("The network adapter failed to be initialized. The adapter requires non-null nodes named \"port\" greater than 0 and smaller or equal to 65535!", e); //$NON-NLS-1$
}
case "xbeeadapter": //$NON-NLS-1$
try {
String port = networkAdapterNode.getChildText("port"); //$NON-NLS-1$
int baudRate = Integer.parseInt(networkAdapterNode.getChildText("baudRate")); //$NON-NLS-1$
return new XbeeAdapter(port, baudRate);
} catch (NumberFormatException nfe) {
throw new BuildException("The network adapter failed to be initialized. The adapter requires non-null nodes named \"port\" and \"baudRate\"!", nfe); //$NON-NLS-1$
} catch (IllegalStateException ise) {
throw new BuildException("The baudRate must be either 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 or 230400!", ise); //$NON-NLS-1$
}
case "bluetoothserver": //$NON-NLS-1$
try {
return new BluetoothServer(networkAdapterNode.getChildText("serviceUuid")); //$NON-NLS-1$
} catch (NullPointerException | IllegalArgumentException e) {
throw new BuildException("The network adapter failed to be initialized. The adapter requires a non-null and well-formed UUID held by a node named \"serviceUuid\"!", e); //$NON-NLS-1$
} catch (IOException ioe) {
throw new BuildException("The adapter could not be set to being discoverable or it failed to open a connection!", ioe); //$NON-NLS-1$
}
case "tcpserver": //$NON-NLS-1$
try {
int port = Integer.parseInt(networkAdapterNode.getChildText("port")); //$NON-NLS-1$
return new TcpServer(port);
} catch (NumberFormatException | IllegalStateException e) {
throw new BuildException("The network adapter failed to be initialized. The adapter requires non-null nodes named \"port\" greater than 0 and smaller or equal to 65535!", e); //$NON-NLS-1$
} catch (IOException ioe) {
throw new BuildException("The socket underlying the TCP server failed to initialize!", ioe); //$NON-NLS-1$
}
default:
throw new BuildException("No network adapter could be initiated for the provided shape archetype: " + archetype); //$NON-NLS-1$
}
}
}
\ No newline at end of file
/**
* Copyright Luxembourg Institute of Science and Technology, 2015. All rights reserved.
*
* This file is part of TULIP.
*
* TULIP 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, version 3 of the
* License.
*
* TULIP 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 Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with TULIP. If
* not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*/
package lu.list.itis.dkd.tui.bootstrapping;
import lu.list.itis.dkd.dbc.annotation.NonNullByDefault;
import lu.list.itis.dkd.dbc.annotation.Nullable;
import lu.list.itis.dkd.tui.exception.BuildException;
import lu.list.itis.dkd.tui.widget.corona.ShapeFactory;
import com.google.common.base.Strings;
import java.awt.Shape;
/**
* Simple bootstrapper to initialize shapes.
*
* @author Eric Tobias [eric.tobias@list.lu]
* @since 2.2
* @version 2.2.0
*/
@NonNullByDefault
public class ShapeBootstrapper {
/**
* Method used to build a {@link Shape} instance given an archetype. The method will delegate
* the construction of the shape to the given public static non-arg build method found in the
* {@link ShapeFactory}.
*
* @param archetype
* The archetype of the shape to build. Supported are:<br>
* <ul>
* <li>Circle</li>
* <li>Rectangle</li>
* <li>RoundedSquare</li>
* <li>Square</li>
* <li>Triangle</li>
* </ul>
* @return A shape as specified by the archetype with dimensions as set by the calibration file.
* Will return <code>null</code> should the archetype by Empty or null.
* @throws BuildException
* Thrown when no archetype could be associated with the provided parameter.
*/
public static @Nullable Shape getShape(@Nullable String archetype) throws BuildException {
if (Strings.isNullOrEmpty(archetype)) {
return null;
}
// TODO The code is currently lacking the ability to add sizes on the fly. This should be
// added in future releases.
switch (archetype.toLowerCase()) {
case "circle": //$NON-NLS-1$
return ShapeFactory.buildCircle();
case "rectangle": //$NON-NLS-1$
return ShapeFactory.buildRectangle();
case "roundedsquare": //$NON-NLS-1$
return ShapeFactory.buildRoundedSquare();
case "square": //$NON-NLS-1$
return ShapeFactory.buildSquare();
case "triangle": //$NON-NLS-1$
return ShapeFactory.buildTriangle();
default:
throw new BuildException("No shape could be initiated for the provided shape archetype: " + archetype); //$NON-NLS-1$
}
}
}
\ No newline at end of file
/**
* Copyright Luxembourg Institute of Science and Technology, 2015. All rights reserved.
*
* This file is part of TULIP.
*