1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.debug.ui;
\r
14 import java.io.File;
\r
15 import java.io.FileNotFoundException;
\r
16 import java.io.IOException;
\r
17 import java.lang.reflect.Array;
\r
18 import java.net.URL;
\r
19 import java.nio.charset.Charset;
\r
20 import java.util.ArrayList;
\r
21 import java.util.Arrays;
\r
22 import java.util.LinkedList;
\r
23 import java.util.TreeMap;
\r
24 import java.util.concurrent.CopyOnWriteArrayList;
\r
25 import java.util.concurrent.atomic.AtomicReference;
\r
27 import org.eclipse.core.runtime.Assert;
\r
28 import org.eclipse.core.runtime.FileLocator;
\r
29 import org.eclipse.core.runtime.IPath;
\r
30 import org.eclipse.core.runtime.Path;
\r
31 import org.eclipse.jface.layout.GridDataFactory;
\r
32 import org.eclipse.jface.resource.ColorDescriptor;
\r
33 import org.eclipse.jface.resource.JFaceResources;
\r
34 import org.eclipse.jface.resource.LocalResourceManager;
\r
35 import org.eclipse.swt.SWT;
\r
36 import org.eclipse.swt.SWTError;
\r
37 import org.eclipse.swt.browser.Browser;
\r
38 import org.eclipse.swt.browser.LocationAdapter;
\r
39 import org.eclipse.swt.browser.LocationEvent;
\r
40 import org.eclipse.swt.dnd.DND;
\r
41 import org.eclipse.swt.dnd.DropTarget;
\r
42 import org.eclipse.swt.dnd.DropTargetAdapter;
\r
43 import org.eclipse.swt.dnd.DropTargetEvent;
\r
44 import org.eclipse.swt.dnd.TextTransfer;
\r
45 import org.eclipse.swt.dnd.Transfer;
\r
46 import org.eclipse.swt.events.DisposeEvent;
\r
47 import org.eclipse.swt.events.DisposeListener;
\r
48 import org.eclipse.swt.events.KeyAdapter;
\r
49 import org.eclipse.swt.events.KeyEvent;
\r
50 import org.eclipse.swt.events.SelectionEvent;
\r
51 import org.eclipse.swt.events.SelectionListener;
\r
52 import org.eclipse.swt.graphics.Color;
\r
53 import org.eclipse.swt.graphics.RGB;
\r
54 import org.eclipse.swt.layout.GridData;
\r
55 import org.eclipse.swt.layout.GridLayout;
\r
56 import org.eclipse.swt.widgets.Button;
\r
57 import org.eclipse.swt.widgets.Composite;
\r
58 import org.eclipse.swt.widgets.Label;
\r
59 import org.eclipse.swt.widgets.Text;
\r
60 import org.simantics.databoard.type.Datatype;
\r
61 import org.simantics.databoard.util.ObjectUtils;
\r
62 import org.simantics.db.ReadGraph;
\r
63 import org.simantics.db.Resource;
\r
64 import org.simantics.db.Session;
\r
65 import org.simantics.db.common.ResourceArray;
\r
66 import org.simantics.db.common.procedure.adapter.DisposableListener;
\r
67 import org.simantics.db.common.request.UnaryRead;
\r
68 import org.simantics.db.common.utils.Logger;
\r
69 import org.simantics.db.exception.DatabaseException;
\r
70 import org.simantics.db.layer0.SelectionHints;
\r
71 import org.simantics.db.layer0.request.PossibleURI;
\r
72 import org.simantics.db.layer0.request.ResourceURIToVariable;
\r
73 import org.simantics.db.layer0.request.VariableURI;
\r
74 import org.simantics.db.layer0.variable.AbstractChildVariable;
\r
75 import org.simantics.db.layer0.variable.AbstractPropertyVariable;
\r
76 import org.simantics.db.layer0.variable.Variable;
\r
77 import org.simantics.db.layer0.variable.VariableNode;
\r
78 import org.simantics.db.layer0.variable.Variables;
\r
79 import org.simantics.db.service.SerialisationSupport;
\r
80 import org.simantics.debug.ui.internal.Activator;
\r
81 import org.simantics.layer0.Layer0;
\r
82 import org.simantics.structural2.variables.Connection;
\r
83 import org.simantics.structural2.variables.VariableConnectionPointDescriptor;
\r
84 import org.simantics.ui.dnd.LocalObjectTransfer;
\r
85 import org.simantics.ui.dnd.ResourceReferenceTransfer;
\r
86 import org.simantics.ui.dnd.ResourceTransferUtils;
\r
87 import org.simantics.ui.utils.ResourceAdaptionUtils;
\r
88 import org.simantics.utils.FileUtils;
\r
89 import org.simantics.utils.bytes.Base64;
\r
90 import org.simantics.utils.ui.ErrorLogger;
\r
91 import org.simantics.utils.ui.ISelectionUtils;
\r
92 import org.simantics.utils.ui.PathUtils;
\r
96 * @author Antti Villberg
\r
97 * @author Tuukka Lehtonen
\r
99 public class VariableDebugger extends Composite {
\r
101 public interface HistoryListener {
\r
102 void historyChanged();
\r
105 private final static String DEFAULT_DEBUGGER_CSS_FILE = "debugger.css";
\r
106 private final static String DEFAULT_DEBUGGER_CSS_PATH = "css/" + DEFAULT_DEBUGGER_CSS_FILE;
\r
108 private static int RESOURCE_NAME_MAX_LENGTH = 1000;
\r
110 private final Charset utf8 = Charset.forName("UTF-8");
\r
112 private final LocalResourceManager resourceManager;
\r
114 private String cssPath;
\r
116 private Text updateTriggerCounter;
\r
117 private Browser browser;
\r
118 private final ColorDescriptor green = ColorDescriptor.createFrom(new RGB(0x57, 0xbc, 0x95));
\r
120 private final LinkedList<String> backHistory = new LinkedList<String>();
\r
121 private final LinkedList<String> forwardHistory = new LinkedList<String>();
\r
122 private String currentElement = null;
\r
125 * The Session used to access the graph. Received from outside of this
\r
126 * class and therefore it is not disposed here, just used.
\r
128 private final Session session;
\r
130 private final CopyOnWriteArrayList<HistoryListener> historyListeners = new CopyOnWriteArrayList<HistoryListener>();
\r
132 protected Layer0 L0;
\r
134 protected boolean disposed;
\r
136 class PageContentListener extends DisposableListener<String> {
\r
137 int triggerCounter;
\r
139 AtomicReference<String> lastResult = new AtomicReference<String>();
\r
141 public void execute(final String content) {
\r
143 //System.out.println("LISTENER TRIGGERED: " + triggerCounter);
\r
144 //System.out.println("LISTENER:\n" + content);
\r
145 if (lastResult.getAndSet(content) == null) {
\r
147 getDisplay().asyncExec(new Runnable() {
\r
149 public void run() {
\r
150 String content = lastResult.getAndSet(null);
\r
151 if (content == null)
\r
155 //System.out.println("UPDATE " + updateCount);
\r
157 if (!browser.isDisposed())
\r
158 browser.setText(content);
\r
159 if (!updateTriggerCounter.isDisposed())
\r
160 updateTriggerCounter.setText(updateCount + "/" + triggerCounter);
\r
168 public void exception(Throwable t) {
\r
169 Logger.defaultLogError(t);
\r
173 private PageContentListener pageContentListener;
\r
179 * @param resource the initial resource to debug or <code>null</code> for
\r
180 * initially blank UI.
\r
182 public VariableDebugger(Composite parent, int style, final Session session, String initialURI) {
\r
183 super(parent, style);
\r
184 Assert.isNotNull(session, "session is null");
\r
185 this.session = session;
\r
186 this.currentElement = initialURI;
\r
187 this.resourceManager = new LocalResourceManager(JFaceResources.getResources(), parent);
\r
191 addDisposeListener(new DisposeListener() {
\r
193 public void widgetDisposed(DisposeEvent e) {
\r
195 PageContentListener l = pageContentListener;
\r
202 public void defaultInitializeUI() {
\r
203 setLayout(new GridLayout(4, false));
\r
204 setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
\r
206 createDropLabel(this);
\r
207 createResourceText(this);
\r
208 createUpdateTriggerCounter(this);
\r
209 Browser browser = createBrowser(this);
\r
210 GridDataFactory.fillDefaults().span(4, 1).grab(true, true).applyTo(browser);
\r
213 protected void initializeCSS() {
\r
214 // Extract default css to a temporary location if necessary.
\r
216 IPath absolutePath = PathUtils.getAbsolutePath(Activator.PLUGIN_ID, DEFAULT_DEBUGGER_CSS_PATH);
\r
217 if (absolutePath != null) {
\r
218 cssPath = absolutePath.toFile().toURI().toString();
\r
220 File tempDir = FileUtils.getOrCreateTemporaryDirectory(false);
\r
221 File css = new File(tempDir, DEFAULT_DEBUGGER_CSS_FILE);
\r
222 if (!css.exists()) {
\r
223 URL url = FileLocator.find(Activator.getDefault().getBundle(), new Path(DEFAULT_DEBUGGER_CSS_PATH), null);
\r
225 throw new FileNotFoundException("Could not find '" + DEFAULT_DEBUGGER_CSS_PATH + "' in bundle '" + Activator.PLUGIN_ID + "'");
\r
226 cssPath = FileUtils.copyResource(url, css, true).toURI().toString();
\r
228 cssPath = css.toURI().toString();
\r
231 } catch (IOException e) {
\r
232 e.printStackTrace();
\r
233 // CSS extraction failed, let's just live without it then.
\r
234 ErrorLogger.defaultLogWarning(e);
\r
238 public Label createDropLabel(Composite parent) {
\r
239 final Label label = new Label(parent, SWT.BORDER | SWT.FLAT);
\r
240 label.setAlignment(SWT.CENTER);
\r
241 label.setText(" Drag a resource or a variable here to examine it in this debugger! ");
\r
242 label.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
\r
243 GridData data = new GridData(SWT.LEFT, SWT.FILL, false, false);
\r
244 label.setLayoutData(data);
\r
246 // Add resource id drop support to the drop-area.
\r
247 DropTarget dropTarget = new DropTarget(label, DND.DROP_LINK | DND.DROP_COPY);
\r
248 dropTarget.setTransfer(new Transfer[] { TextTransfer.getInstance(), ResourceReferenceTransfer.getInstance(), LocalObjectTransfer.getTransfer() });
\r
249 dropTarget.addDropListener(new DropTargetAdapter() {
\r
251 public void dragEnter(DropTargetEvent event) {
\r
252 event.detail = DND.DROP_LINK;
\r
253 label.setBackground((Color) resourceManager.get(green));
\r
257 public void dragLeave(DropTargetEvent event) {
\r
258 label.setBackground(null);
\r
262 public void drop(DropTargetEvent event) {
\r
263 label.setBackground(null);
\r
265 String uri = parseUri(event);
\r
267 event.detail = DND.DROP_NONE;
\r
270 changeLocation(uri);
\r
271 } catch (DatabaseException e) {
\r
272 Logger.defaultLogError(e);
\r
276 private String parseUri(DropTargetEvent event) throws DatabaseException {
\r
277 Variable v = parseVariable(event);
\r
278 String uri = v != null ? session.sync(new VariableURI(v)) : null;
\r
280 Resource r = parseResource(event);
\r
281 uri = r != null ? session.sync(new PossibleURI(r)) : null;
\r
286 private Variable parseVariable(DropTargetEvent event) {
\r
287 return ISelectionUtils.getSinglePossibleKey(event.data, SelectionHints.KEY_MAIN, Variable.class);
\r
290 private Resource parseResource(DropTargetEvent event) throws DatabaseException {
\r
291 ResourceArray[] ra = null;
\r
292 if (event.data instanceof String) {
\r
294 SerialisationSupport support = session.getService(SerialisationSupport.class);
\r
295 ra = ResourceTransferUtils.readStringTransferable(support, (String) event.data).toResourceArrayArray();
\r
296 } catch (IllegalArgumentException e) {
\r
297 e.printStackTrace();
\r
298 } catch (DatabaseException e) {
\r
299 e.printStackTrace();
\r
302 ra = ResourceAdaptionUtils.toResourceArrays(event.data);
\r
304 if (ra != null && ra.length > 0)
\r
305 return ra[0].resources[ra[0].resources.length - 1];
\r
313 public void createResourceText(Composite parent) {
\r
314 final Text text = new Text(parent, SWT.BORDER);
\r
315 GridData data = new GridData(SWT.FILL, SWT.FILL, true, false);
\r
316 text.setLayoutData(data);
\r
318 Button button = new Button(parent, SWT.NONE);
\r
319 button.setText("Lookup");
\r
320 GridData data2 = new GridData(SWT.FILL, SWT.FILL, false, false);
\r
321 button.setLayoutData(data2);
\r
323 button.addSelectionListener(new SelectionListener() {
\r
326 public void widgetDefaultSelected(SelectionEvent e) {
\r
331 public void widgetSelected(SelectionEvent e) {
\r
334 String uri = text.getText();
\r
335 // Make sure that URI is resolvable to Variable
\r
336 session.sync(new ResourceURIToVariable(uri));
\r
337 changeLocation(uri);
\r
338 } catch (DatabaseException e1) {
\r
339 Logger.defaultLogError(e1);
\r
347 protected Text createUpdateTriggerCounter(Composite parent) {
\r
348 Text label = new Text(parent, SWT.BORDER | SWT.FLAT);
\r
349 label.setEditable(false);
\r
350 label.setToolTipText("Amount of Screen/Listener Updates Received for Shown Variable");
\r
351 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL)
\r
352 .grab(false, false).hint(32, SWT.DEFAULT).applyTo(label);
\r
353 updateTriggerCounter = label;
\r
357 public Browser createBrowser(Composite parent) {
\r
359 browser = new Browser(parent, SWT.MOZILLA);
\r
360 } catch (SWTError e) {
\r
361 //System.out.println("Could not instantiate Browser: " + e.getMessage());
\r
362 browser = new Browser(parent, SWT.NONE);
\r
364 browser.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
\r
366 // Left/right arrows for back/forward
\r
367 browser.addKeyListener(new KeyAdapter() {
\r
369 public void keyReleased(KeyEvent e) {
\r
370 // System.out.println("key, char: " + e.keyCode + ", " + (int) e.character + " (" + e.character + ")");
\r
371 // if (e.keyCode == SWT.BS) {
\r
374 if ((e.stateMask & SWT.ALT) != 0) {
\r
375 if (e.keyCode == SWT.ARROW_RIGHT)
\r
377 if (e.keyCode == SWT.ARROW_LEFT)
\r
383 // Add listener for debugging functionality
\r
384 browser.addLocationListener(new LocationAdapter() {
\r
386 public void changing(LocationEvent event) {
\r
387 String location = event.location;
\r
388 if (location.startsWith("simantics:browser"))
\r
389 location = "about:" + location.substring(17);
\r
390 //System.out.println("changing: location=" + location);
\r
392 // Do not follow links that are meant as actions that are
\r
394 event.doit = false;
\r
395 if ("about:blank".equals(location)) {
\r
396 // Just changing to the same old blank url is ok since it
\r
397 // allows the browser to refresh itself.
\r
401 if (location.startsWith("about:-link")) {
\r
402 String target = location.replace("about:-link", "");
\r
404 byte[] bytes = Base64.decode(target);
\r
405 String url = new String(bytes, utf8);
\r
406 if (url.equals(currentElement)) {
\r
407 event.doit = false;
\r
410 changeLocation(url);
\r
411 } catch (IOException e) {
\r
412 ErrorLogger.defaultLogError(e);
\r
414 } else if (location.startsWith("about:-remove")) {
\r
415 } else if (location.startsWith("about:-edit-value")) {
\r
420 // Schedule a request that updates the browser content.
\r
426 public void refreshBrowser() {
\r
427 if (currentElement == null)
\r
430 // Schedule a request that updates the browser content.
\r
431 if (pageContentListener != null)
\r
432 pageContentListener.dispose();
\r
433 pageContentListener = new PageContentListener();
\r
434 session.asyncRequest(new UnaryRead<String, String>(currentElement) {
\r
436 public String perform(ReadGraph graph) throws DatabaseException {
\r
437 String content = calculateContent(graph, parameter);
\r
438 //System.out.println("HTML: " + content);
\r
441 }, pageContentListener);
\r
445 public String getDebuggerLocation() {
\r
446 return currentElement;
\r
449 public void changeLocation(String url) {
\r
450 if (currentElement != null) {
\r
451 backHistory.addLast(currentElement);
\r
453 currentElement = url;
\r
454 forwardHistory.clear();
\r
457 fireHistoryChanged();
\r
460 public void addHistoryListener(HistoryListener l) {
\r
461 historyListeners.add(l);
\r
464 public void removeHistoryListener(HistoryListener l) {
\r
465 historyListeners.remove(l);
\r
468 private void fireHistoryChanged() {
\r
469 for (HistoryListener l : historyListeners)
\r
470 l.historyChanged();
\r
473 public boolean hasBackHistory() {
\r
474 return backHistory.isEmpty();
\r
477 public boolean hasForwardHistory() {
\r
478 return forwardHistory.isEmpty();
\r
481 public void back() {
\r
482 if (backHistory.isEmpty())
\r
485 forwardHistory.addFirst(currentElement);
\r
486 currentElement = backHistory.removeLast();
\r
489 fireHistoryChanged();
\r
492 public void forward() {
\r
493 if (forwardHistory.isEmpty())
\r
496 backHistory.addLast(currentElement);
\r
497 currentElement = forwardHistory.removeFirst();
\r
500 fireHistoryChanged();
\r
503 protected String toName(Object o) {
\r
504 Class<?> clazz = o.getClass();
\r
505 if (clazz.isArray()) {
\r
506 int length = Array.getLength(o);
\r
507 if (length > RESOURCE_NAME_MAX_LENGTH) {
\r
508 if (o instanceof byte[]) {
\r
509 byte[] arr = (byte[]) o;
\r
510 byte[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
\r
511 return truncated("byte", Arrays.toString(arr2), arr.length);
\r
512 } else if (o instanceof int[]) {
\r
513 int[] arr = (int[]) o;
\r
514 int[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
\r
515 return truncated("int", Arrays.toString(arr2), arr.length);
\r
516 } else if (o instanceof long[]) {
\r
517 long[] arr = (long[]) o;
\r
518 long[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
\r
519 return truncated("long", Arrays.toString(arr2), arr.length);
\r
520 } else if (o instanceof float[]) {
\r
521 float[] arr = (float[]) o;
\r
522 float[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
\r
523 return truncated("float", Arrays.toString(arr2), arr.length);
\r
524 } else if (o instanceof double[]) {
\r
525 double[] arr = (double[]) o;
\r
526 double[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
\r
527 return truncated("double", Arrays.toString(arr2), arr.length);
\r
528 } else if (o instanceof boolean[]) {
\r
529 boolean[] arr = (boolean[]) o;
\r
530 boolean[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
\r
531 return truncated("boolean", Arrays.toString(arr2), arr.length);
\r
532 } else if (o instanceof Object[]) {
\r
533 Object[] arr = (Object[]) o;
\r
534 Object[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
\r
535 return truncated("Object", Arrays.toString(arr2), arr.length);
\r
537 return "Unknown big array " + o.getClass();
\r
540 return o.getClass().getComponentType() + "[" + length + "] = " + ObjectUtils.toString(o);
\r
546 protected String truncated(String type, String string, int originalLength) {
\r
547 return type + "[" + RESOURCE_NAME_MAX_LENGTH + "/" + originalLength + "] = " + string;
\r
550 protected String getVariableName(ReadGraph graph, Variable r) {
\r
552 return r.getName(graph);
\r
553 } catch (Exception e) {
\r
554 return e.getMessage();
\r
558 protected String getValue(ReadGraph graph, Variable base, Object o) throws DatabaseException {
\r
559 Class<?> clazz = o.getClass();
\r
560 if(o instanceof Connection) {
\r
561 Connection c = (Connection)o;
\r
562 ArrayList<String> result = new ArrayList<String>();
\r
563 for(VariableConnectionPointDescriptor v : c.getConnectionPointDescriptors(graph, null)) {
\r
564 result.add(v.getRelativeRVI(graph, base));
\r
566 return "c " + result.toString();
\r
567 } else if (clazz.isArray()) {
\r
568 if(int[].class == clazz) {
\r
569 return Arrays.toString((int[])o);
\r
570 } else if(float[].class == clazz) {
\r
571 return Arrays.toString((float[])o);
\r
572 } else if(double[].class == clazz) {
\r
573 return Arrays.toString((double[])o);
\r
574 } else if(long[].class == clazz) {
\r
575 return Arrays.toString((long[])o);
\r
576 } else if(byte[].class == clazz) {
\r
577 return Arrays.toString((byte[])o);
\r
578 } else if(boolean[].class == clazz) {
\r
579 return Arrays.toString((boolean[])o);
\r
580 } else if(char[].class == clazz) {
\r
581 return Arrays.toString((char[])o);
\r
583 return Arrays.toString((Object[])o);
\r
586 return o.toString();
\r
589 protected String getValue(ReadGraph graph, Variable r) {
\r
591 Object value = r.getValue(graph);
\r
592 if(value instanceof Resource) return getResourceRef(graph, (Resource)value);
\r
593 else if (value instanceof Variable) return getVariableRef(graph, (Variable)value);
\r
594 else return value != null ? getValue(graph, r, value) : "null";
\r
595 } catch (Throwable e) {
\r
597 Logger.defaultLogError("getValue " + r.getURI(graph), e);
\r
598 } catch (DatabaseException e1) {
\r
599 Logger.defaultLogError(e1);
\r
601 return e.getMessage();
\r
605 protected String getDatatype(ReadGraph graph, Variable r) {
\r
607 Datatype dt = r.getPossibleDatatype(graph);
\r
608 return dt != null ? dt.toSingleLineString() : "undefined";
\r
609 } catch (Exception e) {
\r
610 return e.getMessage();
\r
614 private String getResourceRef(ReadGraph graph, Resource r) throws DatabaseException {
\r
615 return getVariableRef(graph, graph.adapt(r, Variable.class));
\r
618 private String getVariableRef(ReadGraph graph, Variable r) throws DatabaseException {
\r
619 String ret = "<a href=\"simantics:browser-link" + getLinkString(graph, r) + "\">"
\r
620 + getVariableName(graph, r)
\r
622 // if (graph.isInstanceOf(r, L0.Literal)) {
\r
623 // ret += " <a class=\"edit-link\" href=\"simantics:browser-edit-value" + getLinkString(r) + "\">"
\r
624 // + "(edit value)"
\r
630 private String getLinkString(ReadGraph graph, Variable t) throws DatabaseException {
\r
632 String uri = t.getURI(graph);
\r
634 String encoded = Base64.encode(uri.getBytes(utf8));
\r
636 } catch (Exception e) {
\r
637 Logger.defaultLogError(e);
\r
638 return e.getMessage();
\r
642 private void updateProperty(StringBuilder content, ReadGraph graph, Variable property) throws DatabaseException {
\r
644 // System.out.println("update property " + property.getURI(graph));
\r
645 // } catch (Exception e) {
\r
646 // e.printStackTrace();
\r
648 content.append("<tr>");
\r
649 content.append("<td>").append(getVariableRef(graph, property)).append("</td>");
\r
650 content.append("<td>").append(getValue(graph, property)).append("</td>");
\r
651 content.append("<td>").append(getDatatype(graph, property)).append("</td>");
\r
652 content.append("</tr>");
\r
655 protected String getRVIString(ReadGraph graph, Variable var) throws DatabaseException {
\r
658 return var.getRVI(graph).toString(graph);
\r
659 } catch (Throwable e) {
\r
665 protected synchronized String calculateContent(final ReadGraph graph, String... uris) throws DatabaseException {
\r
667 L0 = Layer0.getInstance(graph);
\r
669 StringBuilder content = new StringBuilder();
\r
671 // Generate HTML -page
\r
672 content.append("<html><head>").append(getHead()).append("</head>\n");
\r
673 content.append("<body>\n");
\r
674 content.append("<div id=\"mainContent\">\n");
\r
675 for (String uri : uris) {
\r
676 //System.out.println("URI: " + uri);
\r
677 Variable var = Variables.getPossibleVariable(graph, uri);
\r
681 String rviString = getRVIString(graph, var);
\r
682 Object node = null;
\r
683 if(var instanceof AbstractChildVariable) {
\r
684 VariableNode vn = ((AbstractChildVariable)var).node;
\r
685 if(vn != null) node = vn.node;
\r
687 if(var instanceof AbstractPropertyVariable) {
\r
688 VariableNode vn = ((AbstractPropertyVariable)var).node;
\r
689 if(vn != null) node = vn.node;
\r
693 content.append("<div id=\"top\">\n");
\r
694 content.append("<table class=\"top\">\n");
\r
695 content.append("<tr><td class=\"top_key\">URI</td><td class=\"top_value\"><span id=\"uri\">").append(uri).append("</span></td></tr>\n");
\r
696 content.append("<tr><td class=\"top_key\">RVI</td><td class=\"top_value\"><span id=\"uri\">").append(rviString).append("</span></td></tr>\n");
\r
697 content.append("<tr><td class=\"top_key\">Class</td><td class=\"top_value\"><span id=\"class\">").append(var.getClass().getCanonicalName()).append("</span></td></tr>\n");
\r
698 content.append("<tr><td class=\"top_key\">Solver node</td><td class=\"top_value\"><span id=\"class\">").append(node).append("</span></td></tr>\n");
\r
699 content.append("</table>\n");
\r
700 content.append("</div>\n");
\r
704 TreeMap<String, Variable> map = new TreeMap<String, Variable>();
\r
706 for(Variable child : var.getChildren(graph)) {
\r
707 String name = getVariableName(graph, child);
\r
708 map.put(name, child);
\r
710 } catch (DatabaseException e) {
\r
711 // This may happen if the Variable implementation is broken
\r
712 ErrorLogger.defaultLogError("Broken variable child retrieval implementation or serious modelling error encountered. See exception for details.", e);
\r
715 TreeMap<String, Variable> map2 = new TreeMap<String, Variable>();
\r
717 for(Variable child : var.getProperties(graph)) {
\r
718 String name = getVariableName(graph, child);
\r
719 map2.put(name, child);
\r
721 } catch (DatabaseException e) {
\r
722 // This may happen if the Variable implementation is broken
\r
723 ErrorLogger.defaultLogError("Broken variable property retrieval implementation or serious modelling error encountered. See exception for details.", e);
\r
726 content.append("\n<div id=\"data\">\n");
\r
727 content.append("<table>\n");
\r
729 content.append("<tr><th>Child</th></tr>");
\r
730 for (Variable child : map.values()) {
\r
731 content.append("<tr><td>").append(getVariableRef(graph, child)).append("</td></tr>");
\r
734 content.append("<tr><th>Property</th><th>Value</th><th>Datatype</th></tr>");
\r
735 for (Variable property : map2.values()) {
\r
736 updateProperty(content, graph, property);
\r
739 content.append("</div>\n\n");
\r
742 // Close #mainContent
\r
743 content.append("</div>\n");
\r
744 content.append("</body></html>\n");
\r
747 return content.toString();
\r
750 private String getHead() {
\r
751 String result = "";
\r
752 if (cssPath != null) {
\r
753 result = "<link href=\"" + cssPath + "\" rel=\"stylesheet\" type=\"text/css\">";
\r