1 /*------------------------------------------------------------------------------
  2 Name:      Transceiver.java
  3 Project:   xmlBlaster.org
  4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
  5 Comment:   Demo code for a svg client using batik
  6 Version:   $Id: Transceiver.java 16476 2007-09-06 22:36:52Z laghi $
  7 ------------------------------------------------------------------------------*/
  8 package javaclients.svg.batik;
  9 
 10 import org.apache.batik.gvt.GraphicsNode;
 11 import org.apache.batik.bridge.BridgeContext;
 12 import java.awt.Point;
 13 
 14 import org.w3c.dom.Element;
 15 import org.w3c.dom.Node;
 16 import org.w3c.dom.Document;
 17 import org.w3c.dom.NamedNodeMap;
 18 import org.w3c.dom.NodeList;
 19 
 20 import java.util.logging.Logger;
 21 import java.util.logging.Level;
 22 import org.xmlBlaster.util.Global;
 23 import org.xmlBlaster.util.XmlBlasterException;
 24 
 25 import org.xmlBlaster.client.I_XmlBlasterAccess;
 26 import org.xmlBlaster.client.I_Callback;
 27 import org.xmlBlaster.client.qos.PublishReturnQos;
 28 import org.xmlBlaster.client.qos.ConnectQos;
 29 import org.xmlBlaster.client.qos.DisconnectQos;
 30 import org.xmlBlaster.client.key.UpdateKey;
 31 import org.xmlBlaster.client.qos.UpdateQos;
 32 import org.xmlBlaster.util.MsgUnit;
 33 import org.xmlBlaster.util.XmlToDom;
 34 import java.io.IOException;
 35 import java.io.FileNotFoundException;
 36 import java.io.FileInputStream;
 37 
 38 import java.util.StringTokenizer;
 39 
 40 /**
 41  * @author $Author: laghi $ (michele@laghi.eu)
 42  */
 43 
 44 public class Transceiver implements I_Callback
 45 {
 46 
 47    private static final String ME = "Transceiver";
 48    private final Global glob;
 49    private static Logger log = Logger.getLogger(Transceiver.class.getName());
 50    private BridgeContext        bridgeContext        = null;
 51    private JSVGCanvasExtended   canvas               = null;
 52    private I_XmlBlasterAccess xmlBlasterConnection = null;
 53    private String               svgFileName          = null;
 54 
 55    private final static String SVG_PREFIX  = "<?xml version='1.0' standalone='no'?>\n<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN'\n'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'><svg>";
 56    private final static String SVG_POSTFIX = "</svg>";
 57 
 58    /**
 59     * ensures that elements are subscribed only one time
 60     */
 61    private boolean elementsSubscribed = false;
 62 
 63 
 64    protected static byte[] readFromFile (String filename)
 65       throws FileNotFoundException, IOException
 66    {
 67       FileInputStream fileInputStream = new FileInputStream(filename);
 68       int fileSize = fileInputStream.available();
 69       byte[] b = new byte[fileSize];
 70       fileInputStream.read(b);
 71       return b;
 72    }
 73 
 74 
 75    public void subscribeElements () throws XmlBlasterException
 76    {
 77       if ((this.svgFileName != null) && (this.elementsSubscribed == false)) {
 78          String xmlKey = "<?xml version='1.0' encoding='ISO-8859-1' ?>\n" +
 79                       "<key oid='' queryType='XPATH'>\n" +
 80                       "   //svg[@name='" + this.svgFileName + "' and @complete='false']" +
 81                       "</key>";
 82          String qos = "<qos></qos>";
 83          this.xmlBlasterConnection.subscribe(xmlKey, qos);
 84          this.elementsSubscribed = true;
 85       }
 86    }
 87 
 88 
 89    /**
 90     * In the argument list you should have either
 91     * -svgMaster filename
 92     * -svgSlave filename
 93     */
 94    public Transceiver (Global glob, JSVGCanvasExtended canvas)
 95    {
 96       this.glob = glob;
 97 
 98       log.fine("constructor with Global");
 99       this.canvas = canvas;
100       try {
101          String svgMaster = glob.getProperty().get("svgMaster", (String)null);
102          String svgSlave  = glob.getProperty().get("svgSlave", (String)null);
103          String svgUser   = glob.getProperty().get("svgUser", "dummyUser");
104 
105          this.xmlBlasterConnection = glob.getXmlBlasterAccess();
106          ConnectQos connectQos = new ConnectQos(glob, svgUser, "secret");
107          this.xmlBlasterConnection.connect(connectQos, this);
108 
109 
110          if (svgMaster != null) {
111             this.svgFileName = svgMaster;
112             log.fine("constructor: running as Master: " + svgMaster);
113             // read the file, create a publishKey and then publish the thing
114             // then subscribe only to complete documents (not single elements)
115             // this because the elements can olny be updated once the document
116             // has been loaded.
117             String xmlKey = "<key oid=''><svg name='" + this.svgFileName + "' complete='true'></svg></key>";
118             String qos = "<qos></qos>";
119             // retrieve the file content
120             byte[] content = this.readFromFile(this.svgFileName);
121             MsgUnit messageUnit = new MsgUnit(xmlKey, content, qos);
122             PublishReturnQos ret = this.xmlBlasterConnection.publish(messageUnit);
123             log.info("constructor: " + ret.getKeyOid());
124          }
125          else if (svgSlave != null) {
126             this.svgFileName = svgSlave;
127          }
128 
129          if (this.svgFileName != null) {
130             String xmlKey = "<?xml version='1.0' encoding='ISO-8859-1' ?>\n" +
131                       "<key oid='' queryType='XPATH'>\n" +
132                       "   //svg[@name='" + this.svgFileName + "' and @complete='true']" +
133                       "</key>";
134             String qos = "<qos></qos>";
135             this.xmlBlasterConnection.subscribe(xmlKey, qos);
136          }
137       }
138       // don't know if this is the correct place where to catch this exception
139       catch (XmlBlasterException ex) {
140          log.severe("Transceiver Constructor: " + ex.toString());
141       }
142       catch (FileNotFoundException ex) {
143          log.severe("Transceiver Constructor: " + ex.toString());
144       }
145       catch (IOException ex) {
146          log.severe("Transceiver Constructor: " + ex.toString());
147       }
148    }
149 
150 
151    /**
152     * Disconnects from the xmlBlaster Server
153     */
154    public void disconnect ()
155    {
156       this.xmlBlasterConnection.disconnect(new DisconnectQos(glob));
157    }
158 
159 
160    /**
161     * This method is invoked when a whole document is sent (this should be the
162     * first update this object should receive).
163     */
164    protected void updateDocument (byte[] content) throws XmlBlasterException
165    {
166       log.warning(".updateDocument()");
167       try {
168          this.canvas.loadDocumentFromByteArray(content);
169       }
170       catch (IOException ex)
171       {
172          log.severe("io exception: " + ex.toString());
173          throw new XmlBlasterException(ME, ".updateDocument: " + ex.getMessage());
174       }
175    }
176 
177 
178    protected void updateElement (byte[] content, String id) throws XmlBlasterException
179    {
180       log.fine(".updateElement(): " + id);
181 
182       Element el = this.canvas.getElement(id);
183       if (el == null) {
184          log.warning("the element with id '" + id + "' is not registered");
185          return;
186       }
187 
188       this.bridgeContext.unbind(el);
189       String completeSVG = SVG_PREFIX + new String(content) + SVG_POSTFIX;
190       log.warning(".updateElement: " + completeSVG);
191 
192       try {
193          Node tempNode = SvgUtility.createDocument(completeSVG, "file://dummy.svg").getDocumentElement().getFirstChild();
194 
195          Document doc = el.getOwnerDocument();
196          tempNode = doc.importNode(tempNode, true);
197 
198          Node parentNode = el.getParentNode();
199          parentNode.replaceChild(tempNode, el);
200 
201          GraphicsNode graphicsNode = this.bridgeContext.getGVTBuilder().build(this.bridgeContext, (Element)tempNode);
202          this.bridgeContext.bind((Element)tempNode, graphicsNode);
203 
204          graphicsNode = this.bridgeContext.getGVTBuilder().build(this.bridgeContext, tempNode.getOwnerDocument());
205          this.canvas.setGraphicsNode(graphicsNode);
206          this.canvas.updateDocument();
207       }
208       catch (IOException ex) {
209          log.severe(".updateElement: IOException " + ex.getMessage());
210          throw new XmlBlasterException(ME, ".updateElement: IOException " + ex.getMessage());
211       }
212    }
213 
214 
215 
216    public String update(java.lang.String loginName, UpdateKey updateKey,
217                    byte[] content, UpdateQos updateQos) throws XmlBlasterException
218    {
219       log.fine("update called, content: " + new String(content));
220       log.fine("update called, loginName: " + loginName);
221       log.fine("update called, updateKey: " + updateKey);
222       log.fine("update called, updateQos: " + updateQos);
223 
224       NodeList nodes = XmlToDom.parseToDomTree(glob, updateKey.toString()).getDocumentElement().getElementsByTagName("svg");
225       int length = nodes.getLength();
226       if ((nodes == null) || (length < 1)) {
227          throw new XmlBlasterException(ME, ".update: no svg node found in the key");
228       }
229 
230       Node keyNode = nodes.item(0);
231       if (keyNode instanceof Element) {
232          // if an id has been defined, then it is a single element otherwise the whole document
233          String id = ((Element)keyNode).getAttribute("id");
234          if ((id == null) || (id.length() < 1)) {
235             updateDocument(content);
236          }
237          else updateElement(content, id);
238       }
239       else throw new XmlBlasterException(ME, "update: svg node is not an element");
240       return "";
241    }
242 
243 
244 
245    public void setBridgeContext (BridgeContext bridgeContext)
246    {
247       this.bridgeContext = bridgeContext;
248    }
249 
250 
251    /**
252     * finds if the given element is in the idTable (i.e. if it does not
253     * fullfill the 'dynamic' requirements). If not, its parent is searched and
254     * so on. If the element nor one of its ancestors is dynamic, it returns
255     * null, otherwise it returns the first dynamic element found.
256     *
257     * Currently the requirements for dynamic is that the element has an id
258     * which has a prefix 'xmlBlaster:'
259     */
260    protected Element getClickedDynamicElement (Element el)
261    {
262       log.fine(".getClickedDynamicElement");
263       while (el != null) {
264          String id = el.getAttribute("id");
265          if (SvgIdMapper.isDynamic(id)) return el;
266          Node parent = el.getParentNode();
267          if (parent instanceof Element) el = (Element)parent;
268          else return null;
269       }
270       return null;
271    }
272 
273 
274    public static void moveElement (Element el, int x, int y)
275    {
276       //log.finer(".moveElement");
277       if (el == null) return;
278       String transformString = el.getAttribute("transform");
279       if ((transformString == null) || (transformString.length() < 1)) {
280          transformString = "translate(" + x + "," + y + ")";
281       }
282       else {
283          el.removeAttribute("transform");
284          // check if 'translate' is defined
285          int pos = transformString.indexOf("translate(");
286          if (pos < 0) transformString += " translate(" + x + "," + y + ")";
287          else { // get the position string
288             String endString   = transformString.substring(pos + "translate(".length()).trim();
289             String startString = transformString.substring(0, pos).trim();
290             String coreString  = endString.substring(0, endString.indexOf(")")).trim();
291             endString          = endString.substring(1 + endString.indexOf(")")).trim();
292             StringTokenizer tokenizer = new StringTokenizer(coreString,",");
293 
294             double x0 = Double.parseDouble(tokenizer.nextToken().trim());
295             double y0 = Double.parseDouble(tokenizer.nextToken().trim());
296 
297             transformString = startString + " translate(" + (x0 + x) + "," + (y0 + y) + ") " + endString;
298          }
299       }
300       el.setAttribute("transform", transformString);
301    }
302 
303    public void move (GraphicsNode graphicsNode, Point displacement)
304    {
305       log.info(".move " + displacement.x + " " + displacement.y);
306 
307       Element el = this.bridgeContext.getElement(graphicsNode);
308       el = getClickedDynamicElement(el);
309       if (el == null) return;
310 
311       String id = el.getAttribute("id");
312 
313       // later make the necessary transform ....
314       this.moveElement(el, displacement.x, displacement.y);
315 
316    /*
317       double x = graphicsNode.getBounds().getMinX() + displacement.x;
318       double y = graphicsNode.getBounds().getMinY() + displacement.y;
319 
320       el.setAttributeNS(null, "x", Double.toString(x));
321       el.setAttributeNS(null, "y", Double.toString(y));
322 */
323       log.info(".move: el: " + el.getNodeName());
324 
325 
326       // publish the node
327       String xmlKey = "<key oid=''><svg name='" + this.svgFileName + "' id='" + id + "' complete='false'></svg></key>";
328       String qos = "<qos></qos>";
329       // retrieve the file content
330       byte[] content = XmlUtility.write(el).getBytes();
331 
332       try {
333          MsgUnit messageUnit = new MsgUnit(xmlKey, content, qos);
334          PublishReturnQos ret = this.xmlBlasterConnection.publish(messageUnit);
335          log.fine("move: " + ret.getKeyOid());
336       }
337       catch (XmlBlasterException ex) {
338          log.severe(".move exception when publishing: " + ex.getMessage());
339       }
340    }
341 
342 }


syntax highlighted by Code2HTML, v. 0.9.1