Tutorial: Quickstart

From Developer Documents
Revision as of 09:16, 14 October 2010 by Tuukka Lehtonen (talk | contribs)
Jump to navigation Jump to search

Quickstart

Client opens a database session

To open a client session to a Simantics database server you need to fetch a Driver (javadoc) from the Driver manager (javadoc).

The basic idea is much the same as in JDBC Driver and DriverManager.

<syntaxhighlight lang="java">

   // Try to load and register the Driver instance with the driver manager
   Class.forName("fi.vtt.simantics.procore.ProCoreDriver");
   // Connect to the server at the specified host and credentials.
   Session session = Manager.getSession("procore", InetSocketAddress.createUnresolved("localhost", port), username, password);

</syntaxhighlight>

Reading the database

Synchronous primitive read

<syntaxhighlight lang="java">

   Boolean readBooleanProperty(RequestProcessor processor, final Resource resource, final Resource property) {
       return processor.syncRequest(new Read<Boolean>() {
           public Boolean perform(ReadGraph graph) throws DatabaseException {
               return graph.getRelatedValue(resource, property);
           }
       });
   }

</syntaxhighlight>

Writing the database

Synchronous write requests

<syntaxhighlight lang="java">

   Resource createLibrary(WriteGraph graph) throws DatabaseException {
       Builtins b = graph.getBuiltins();
       // Create new Library instance. Use claim(s,p,inv,o)
       // instead of claim(s,p,o) for defining (s, InstanceOf, o)
       // to not create the inverse statement (o, HasInstance, s).
       Resource library = graph.newResource();
       graph.claim(library, b.InstanceOf, null, b.Library);
       // Give the library a name
       graph.claimValue(library, b.HasName, "New Library");
       // Attach the library to the specified container
       graph.claim(container, b.ConsistsOf, library);
   }
   class CreateLibrary extends AbstractWriteResult<Resource> {
       Resource container;
       public CreateLibrary(Resource container) {
           this.container = container;
       }
       public Resource perform(WriteGraph graph) throws DatabaseException {
           return createLibrary(graph);
       }
   }
   void createLibrary(RequestProcessor processor, Resource container) {
       processor.syncRequest(new CreateLibrary(container));
   }

</syntaxhighlight>

Class Diagrams

File:Db1.graphml

Database session-level class hierarchy. Use these to manage the session and initiate read and write requests (transactions). Requests can be initiated either synchronously or asynchronously. Synchronous invocations will not return before the request has completed/failed while asynchronous requests will return immediately and completion/failure will be notified through a separate Procedure.
File:Db2.graphml

Classes related to accessing the graph database during read and write transactions. ReadGraph, AsyncReadGraph, WriteGraph and WriteOnlyGraph are the only way to access the actual statements and values in the database. ReadGraph is a good place to get started.
File:Db3.graphml

This image shows all the different kinds of requests that can be performed through RequestProcessor and AsyncRequestProcessor. Beginners should focus on interfaces Read<T> and Write. Note that these request classes have default implementations that should be extended instead of directly implementing the interfaces. See the classes for more info.
File:Db4.graphml

This image shows the listener and procedure interfaces that can be used along with the read requests for one of two reasons: 1. the read requests were made asynchronously so completion can be reported through a Procedure, 2. the client wants to listen to changes in the result of the performed request. Listeners have a lifecycle determined by their disposedness.

Repairing corrupted database

When running the database in debug mode a complete journal of all the changes made to the database is kept. If an error is encountered during a change the erroneous command is written to the journal and the database will stop servicing requests. The journal can be used to initialize the database by reading it to an empty database. This can be done by:

  • rename journal.procore file to journalRepair.procore
  • delete or rename other *.procore files so that you have empty database
  • start server

FAQ

Q: Why can't I initialize my Workbench/SWT UI within a synchronous database read request? When I try to do this, SWTError Invalid thread access is thrown. I used to be able to do this before!

Excerpt from RequestProcessor javadoc:

A client invoking any of the syncRequest-methods in this interface must not assume that the request is performed within the same thread that performed the syncRequest invocation. This is an implementation-specific matter.

Granted, before 2009 the implementation was such that it would execute synchronous requests within the invoking thread but it is now specified as seen above. Note that you cannot synchronously schedule access to another thread and use the original ReadGraph/AsyncReadGraph from there since database access is tied to the dedicated threads assigned for it.

Q: My write transaction was interrupted by unexpected exception. Why am I still seeing parts of the unfinished write operation in my database? What happened to rollback?

The current DB client implementation does properly support write request rollback, which unfortunately causes the DB client's view of the database to be corrupted. Also if your write operation is not small, even the server's view of the database may be corrupted. At the moment it looks like resolving this issue will be delayed until Simantics 1.2. Until then, the Simantics database cannot be considered for continuous use in any real-life applications.