--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.simantics.jdbc.ontology</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.simantics.graph.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.simantics.graph.nature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
--- /dev/null
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: http://www.simantics.org/JDBC-1.0
+Bundle-SymbolicName: org.simantics.jdbc.ontology
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.simantics.jdbc.ontology.Activator
+Require-Bundle: org.eclipse.core.runtime,
+ org.simantics.layer0,
+ org.simantics.selectionview.ontology;bundle-version="1.2.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-ActivationPolicy: lazy
+Export-Package: org.simantics.jdbc
--- /dev/null
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ graph.tg
--- /dev/null
+L0 = <http://www.simantics.org/Layer0-1.1>
+SEL = <http://www.simantics.org/SelectionView-1.2>
+
+JDBC = <http://www.simantics.org/JDBC-1.0> : L0.Ontology
+ @L0.new
+ L0.HasResourceClass "org.simantics.jdbc.JDBCResource"
+
+JDBC.Session <T L0.Entity
+ >-- JDBC.Session.hasValue --> L0.Value <R L0.HasProperty : SEL.GenericParameterType
+
\ No newline at end of file
--- /dev/null
+package org.simantics.jdbc.ontology;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator {
+
+ private static BundleContext context;
+
+ static BundleContext getContext() {
+ return context;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext bundleContext) throws Exception {
+ Activator.context = bundleContext;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext bundleContext) throws Exception {
+ Activator.context = null;
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>\r
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+ <classpathentry kind="src" path="src"/>\r
+ <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.simantics.jdbc</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.simantics.graph.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.simantics.graph.nature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
--- /dev/null
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Simantics JDBC support
+Bundle-SymbolicName: org.simantics.jdbc
+Bundle-Version: 1.0.0.qualifier
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-ClassPath: .
+Require-Bundle: org.eclipse.osgi,
+ org.simantics.simulator.toolkit,
+ org.simantics.databoard,
+ gnu.trove3;bundle-version="3.0.3",
+ org.slf4j.api;bundle-version="1.7.25",
+ org.simantics.db.layer0,
+ org.simantics.simulator.toolkit.db,
+ org.simantics,
+ org.simantics.jdbc.ontology,
+ io.netty.buffer;bundle-version="4.1.27",
+ io.netty.codec;bundle-version="4.1.27",
+ io.netty.common;bundle-version="4.1.27",
+ io.netty.handler;bundle-version="4.1.27",
+ io.netty.transport;bundle-version="4.1.27",
+ pgjdbc-ng;bundle-version="0.7.1"
+Export-Package: org.simantics.jdbc,
+ org.simantics.jdbc.variable
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<adapters>
+ <target interface="org.simantics.db.layer0.variable.VariableBuilder">
+ <type uri="http://www.simantics.org/JDBC-1.0/Session" class="org.simantics.jdbc.variable.JDBCVariableBuilder" />
+ </target>
+</adapters>
\ No newline at end of file
--- /dev/null
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ adapters.xml,\
+ jdbc.properties
--- /dev/null
+simantics.jdbc.host=127.0.0.1
+simantics.jdbc.port=5432
+simantics.jdbc.user=simantics
+simantics.jdbc.password=simantics
+simantics.jdbc.database=simantics
\ No newline at end of file
--- /dev/null
+package org.simantics.jdbc;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.util.Layer0Utils;
+import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.layer0.variable.Variables;
+import org.simantics.layer0.Layer0;
+
+/**
+ * Simantics JDBC facade.
+ *
+ * @author Jani Simomaa
+ */
+public class SimanticsJDBC {
+
+ public static final String PROP_SIMANTICS_JDBC_PROPERTYFILE = "simantics.jdbc.propertyfile";
+ public static final String PROP_SIMANTICS_JDBC_HOST = "simantics.jdbc.host";
+ public static final String PROP_SIMANTICS_JDBC_PORT = "simantics.jdbc.port";
+ public static final String PROP_SIMANTICS_JDBC_USER = "simantics.jdbc.user";
+ public static final String PROP_SIMANTICS_JDBC_PASSWORD = "simantics.jdbc.password";
+ public static final String PROP_SIMANTICS_JDBC_DATABASE = "simantics.jdbc.database";
+
+ public static String createJDBCSession(WriteGraph graph, String sessionGUID) throws DatabaseException {
+ Resource projects = graph.getResource("http://Projects");
+ Resource documentSessions = Layer0Utils.getPossibleChild(graph, projects, "DocumentSessions");
+ Layer0 L0 = Layer0.getInstance(graph);
+ Resource documentSession = Layer0Utils.getPossibleChild(graph, documentSessions, sessionGUID);
+
+ String sessionId = "http://Projects/DocumentSessions/" + sessionGUID + "/__jdbc__";
+
+ JDBCResource JDBC = JDBCResource.getInstance(graph);
+ Resource jdbcSession = graph.newResource();
+ graph.claim(jdbcSession, L0.InstanceOf, JDBC.Session);
+ graph.claimLiteral(jdbcSession, L0.HasName, L0.NameOf, L0.String, "__jdbc__", Bindings.STRING);
+ graph.claim(documentSession, L0.ConsistsOf, jdbcSession);
+
+ @SuppressWarnings("unused")
+ Variable jdbcState = Variables.getVariable(graph, jdbcSession);
+
+ return sessionId;
+ }
+}
--- /dev/null
+package org.simantics.jdbc.internal;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator {
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+
+ }
+
+}
--- /dev/null
+package org.simantics.jdbc.variable;
+
+import org.simantics.simulator.toolkit.StandardNode;
+
+public class JDBCNode implements StandardNode {
+
+ public String name;
+
+ public JDBCNode(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ JDBCNode other = (JDBCNode) obj;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ return true;
+ }
+}
--- /dev/null
+package org.simantics.jdbc.variable;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.simantics.simulator.toolkit.StandardNodeManager;
+import org.simantics.simulator.toolkit.StandardRealm;
+import org.simantics.simulator.variable.exceptions.NodeManagerException;
+
+public class JDBCNodeManager extends StandardNodeManager<JDBCNode, JDBCNodeManagerSupport> {
+
+ public JDBCNodeManager(StandardRealm<JDBCNode, JDBCNodeManagerSupport> realm, JDBCNode root) {
+ super(realm, root);
+ }
+
+ @Override
+ public Set<String> getClassifications(JDBCNode node) throws NodeManagerException {
+ return Collections.emptySet();
+ }
+
+}
--- /dev/null
+package org.simantics.jdbc.variable;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.simulator.toolkit.StandardNodeManagerSupport;
+import org.simantics.simulator.variable.exceptions.NodeManagerException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.impossibl.postgres.api.jdbc.PGConnection;
+import com.impossibl.postgres.jdbc.PGDataSource;
+
+public class JDBCNodeManagerSupport implements StandardNodeManagerSupport<JDBCNode> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(JDBCNodeManagerSupport.class);
+ @SuppressWarnings("unused")
+ private String id; // this might have some use later in the future?
+ private PGDataSource dataSource;
+ private String channelName;
+
+ public JDBCNodeManagerSupport(String id, PGDataSource dataSource, String channelName) {
+ this.id = id;
+ this.dataSource = dataSource;
+ this.channelName = channelName;
+ }
+
+ @Override
+ public Object getEngineValue(JDBCNode node) throws NodeManagerException {
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Getting value for {}", node.getName());
+
+ try (PGConnection connection = (PGConnection) dataSource.getConnection()) {
+ // do get value
+ PreparedStatement ps = connection.prepareStatement("SELECT value->'value' FROM simantics_table WHERE key IN ('" + node.getName() + "');");
+ ResultSet rs = ps.executeQuery();
+ if (!rs.next()) {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("no value for query {}", ps.toString());
+ }
+ return null;
+ }
+ return rs.getObject(1);
+ } catch (Exception e) {
+ LOGGER.error("Failed to get value for {}", node.getName(), e);
+ throw new NodeManagerException("Failed to get value for " + node.getName(), e);
+ }
+ }
+
+ @Override
+ public Binding getEngineBinding(JDBCNode node) throws NodeManagerException {
+ return Bindings.OBJECT;
+ }
+
+ @Override
+ public void setEngineValue(JDBCNode node, Object value) throws NodeManagerException {
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Setting value for {} to {}", node.getName(), value);
+
+ setValueImpl(node.getName(), value);
+ }
+
+ private void setValueImpl(String name, Object value) throws NodeManagerException {
+ try (PGConnection connection = (PGConnection) dataSource.getConnection()) {
+ // do set value
+ PreparedStatement statement = connection.prepareStatement("INSERT INTO simantics_table VALUES (?, ?::JSON) ON CONFLICT (key) DO UPDATE SET value= ?::JSON");
+ statement.setString(1, name);
+ statement.setObject(2, "{\"value\": " + value.toString() + "}");
+ statement.setObject(3, "{\"value\": " + value.toString() + "}");
+ statement.executeUpdate();
+
+ // notify others (including ourselves)
+ doNotify(connection, name);
+ } catch (Exception e) {
+ LOGGER.error("Failed to set value for {} to {}", name, value, e);
+ throw new NodeManagerException("Failed to set value for " + name + " to " + String.valueOf(value), e);
+ }
+ }
+
+ private void doNotify(PGConnection connection, String name) throws SQLException {
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Notifying change {} to channel {}", name, this.channelName);
+ Statement statement = connection.createStatement();
+ String sql = "NOTIFY " + this.channelName + ", '" + name + "'";
+ statement.execute(sql);
+ statement.close();
+ }
+
+ @Override
+ public String getName(JDBCNode node) {
+ return node.getName();
+ }
+
+ @Override
+ public Map<String, JDBCNode> getChildren(JDBCNode node) {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public Map<String, JDBCNode> getProperties(JDBCNode node) {
+ HashMap<String, JDBCNode> properties = new HashMap<>();
+ try (PGConnection connection = (PGConnection) dataSource.getConnection()) {
+ Statement st = connection.createStatement();
+ ResultSet executeQuery = st.executeQuery("SELECT key FROM simantics_table");
+ while (executeQuery.next()) {
+ String key = executeQuery.getString(1);
+ properties.put(key, new JDBCNode(key));
+ }
+ } catch (Exception e) {
+ LOGGER.error("Could not read properties", e);
+ }
+
+ return properties;
+ }
+
+}
--- /dev/null
+package org.simantics.jdbc.variable;
+
+import org.simantics.simulator.toolkit.StandardNodeManager;
+import org.simantics.simulator.toolkit.StandardRealm;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JDBCRealm extends StandardRealm<JDBCNode, JDBCNodeManagerSupport> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(JDBCRealm.class);
+
+ protected JDBCRealm(JDBCNodeManagerSupport engine, String id) {
+ super(engine, id);
+ }
+
+ @Override
+ protected StandardNodeManager<JDBCNode, JDBCNodeManagerSupport> createManager() {
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Creating {} for realm with id {}", JDBCNodeManager.class.getSimpleName(), getId());
+ return new JDBCNodeManager(this, new JDBCNode("ROOT"));
+ }
+
+ @Override
+ public Logger getLogger() {
+ return LOGGER;
+ }
+
+}
--- /dev/null
+package org.simantics.jdbc.variable;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.nio.file.Paths;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Properties;
+import java.util.function.Function;
+
+import org.simantics.Simantics;
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.binding.error.BindingException;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.common.request.ReadRequest;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.variable.NodeSupport;
+import org.simantics.jdbc.SimanticsJDBC;
+import org.simantics.simulator.toolkit.StandardRealm;
+import org.simantics.simulator.toolkit.db.StandardSessionManager;
+import org.simantics.simulator.variable.exceptions.NodeManagerException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.impossibl.postgres.api.jdbc.PGConnection;
+import com.impossibl.postgres.api.jdbc.PGNotificationListener;
+import com.impossibl.postgres.jdbc.PGDataSource;
+
+public class JDBCSessionManager extends StandardSessionManager<JDBCNode, JDBCNodeManagerSupport> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(JDBCSessionManager.class);
+ private static JDBCSessionManager INSTANCE = new JDBCSessionManager();
+
+ private static final String VALUE_SIMANTICS_JDBC_HOST = "localhost";
+ private static final int VALUE_SIMANTICS_JDBC_PORT = 5432;
+ private static final String VALUE_SIMANTICS_JDBC_USER = "simantics";
+ private static final String VALUE_SIMANTICS_JDBC_PASSWORD = "simantics";
+ private static final String VALUE_SIMANTICS_JDBC_DATABASE = "simantics";
+
+ private String channelName;
+ private PGNotificationListener listener;
+
+ private PGDataSource dataSource;
+ private Connection connection;
+
+ private static Properties readProperties(InputStream s) throws IOException {
+ try (InputStream is = s) {
+ Properties props = new Properties();
+ props.load(is);
+ return props;
+ }
+ }
+
+ private static Properties safeReadProperties(URL url) {
+ try {
+ return readProperties(url.openStream());
+ } catch (IOException e) {
+ LOGGER.error("Could not read props from " + url, e);
+ return null;
+ }
+ }
+
+ private static Properties safeReadProperties(URI uri) {
+ try {
+ return safeReadProperties(uri.toURL());
+ } catch (MalformedURLException e) {
+ LOGGER.error("Could not read props from " + uri, e);
+ return null;
+ }
+ }
+
+ private static Properties safeReadProperties(String path) {
+ return safeReadProperties(Paths.get(path).toUri());
+ }
+
+ private static Properties readProperties() {
+ String propFile = System.getProperty(SimanticsJDBC.PROP_SIMANTICS_JDBC_PROPERTYFILE, null);
+ if (propFile != null) {
+ Properties p = safeReadProperties(propFile);
+ if (p != null)
+ return p;
+ }
+ // Read default settings from built-in file and override them with values in System properties
+ Properties p = safeReadProperties(JDBCSessionManager.class.getClassLoader().getResource("jdbc.properties"));
+ if (p != null) {
+ p.putAll(System.getProperties());
+ } else {
+ p = System.getProperties();
+ }
+ return p;
+ }
+
+ public JDBCSessionManager() {
+ this.channelName = "test";
+
+ Properties props = readProperties();
+ String host = props.getProperty(SimanticsJDBC.PROP_SIMANTICS_JDBC_HOST, VALUE_SIMANTICS_JDBC_HOST);
+ String port = props.getProperty(SimanticsJDBC.PROP_SIMANTICS_JDBC_PORT, "" + VALUE_SIMANTICS_JDBC_PORT);
+ String database = props.getProperty(SimanticsJDBC.PROP_SIMANTICS_JDBC_DATABASE, VALUE_SIMANTICS_JDBC_DATABASE);
+ String user = props.getProperty(SimanticsJDBC.PROP_SIMANTICS_JDBC_USER, VALUE_SIMANTICS_JDBC_USER);
+ String password = props.getProperty(SimanticsJDBC.PROP_SIMANTICS_JDBC_PASSWORD, VALUE_SIMANTICS_JDBC_PASSWORD);
+
+ try {
+ int portNumber = Integer.valueOf(port);
+
+ dataSource = new PGDataSource();
+ dataSource.setHost(host);
+ dataSource.setPort(portNumber);
+ dataSource.setDatabase(database);
+ dataSource.setUser(user);
+ dataSource.setPassword(password);
+
+ this.connection = dataSource.getConnection();
+ this.listener = new PGNotificationListener() {
+ @Override
+ public void notification(int processId, String channelName, String payload) {
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Received notification from processId={} channelName={} and payload={}", processId, channelName, payload);
+ Simantics.getSession().asyncRequest(new ReadRequest() {
+ @Override
+ public void run(ReadGraph graph) throws DatabaseException {
+ for (String realmId : INSTANCE.getRealms()) {
+ try {
+ JDBCRealm jdbcRealm = (JDBCRealm) INSTANCE.getOrCreateRealm(graph, realmId);
+ jdbcRealm.getNodeManager().refreshVariable(new JDBCNode(payload));
+ } catch (DatabaseException e) {
+ LOGGER.error("Could not refresh variable in realm {} with payload {}", realmId, payload, e);
+ }
+ }
+ }
+ });
+ }
+ };
+ createTable();
+ init();
+ } catch (SQLException e) {
+ LOGGER.error("Could not initialize JDBCSessionManager!", e);
+ }
+ }
+
+ private void createTable() throws SQLException {
+ Statement statement = connection.createStatement();
+ statement.execute("CREATE TABLE IF NOT EXISTS simantics_table (key VARCHAR UNIQUE, value JSON)");
+ statement.close();
+ }
+
+ protected void init() throws SQLException {
+ Statement statement = connection.createStatement();
+ statement.execute("LISTEN " + this.channelName);
+ statement.close();
+ ((PGConnection) connection).addNotificationListener(this.listener);
+ }
+
+ protected void destroy() throws SQLException {
+ try (PGConnection connection = (PGConnection) dataSource.getConnection()) {
+ Statement statement = connection.createStatement();
+ statement.execute("UNLISTEN " + this.channelName);
+ statement.close();
+ }
+ }
+
+
+ @Override
+ protected JDBCNodeManagerSupport createEngine(ReadGraph graph, String id) throws DatabaseException {
+ return new JDBCNodeManagerSupport(id, this.dataSource, this.channelName);
+ }
+
+ @Override
+ protected StandardRealm<JDBCNode, JDBCNodeManagerSupport> createRealm(JDBCNodeManagerSupport engine, String id) {
+ return new JDBCRealm(engine, id);
+ }
+
+ public static void setValue(ReadGraph graph, String id, String key, Object value) throws DatabaseException, NodeManagerException, BindingException, InterruptedException {
+ JDBCRealm realm = (JDBCRealm) INSTANCE.getOrCreateRealm(graph, id);
+ realm.asyncExec(() -> {
+ try {
+ realm.getNodeManager().setValue(new JDBCNode(key), key, value, Bindings.OBJECT);
+ } catch (NodeManagerException | BindingException e) {
+ LOGGER.error("Could not set value {} for {}", value, key, e);
+ }
+ });
+ }
+
+ public static NodeSupport<?> nodeSupport(ReadGraph graph, String sessionName) throws DatabaseException {
+ return INSTANCE.getOrCreateNodeSupport(graph, sessionName);
+ }
+
+ public static Object getValue(ReadGraph graph, String uri, String key) throws InterruptedException, DatabaseException {
+ JDBCRealm realm = (JDBCRealm) INSTANCE.getOrCreateRealm(graph, uri);
+ return realm.syncExec(new Function<Object, Object>() {
+
+ @Override
+ public Object apply(Object t) {
+ try {
+ return realm.getNodeManager().getValue(new JDBCNode(key), key).getValue();
+ } catch (NodeManagerException e) {
+ LOGGER.error("Could not get value for {}", key, e);
+ return null;
+ }
+ }
+ });
+ }
+
+}
--- /dev/null
+package org.simantics.jdbc.variable;
+
+import org.simantics.db.ReadGraph;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.variable.NodeManagerVariableBuilder;
+import org.simantics.db.layer0.variable.NodeSupport;
+
+public class JDBCVariableBuilder extends NodeManagerVariableBuilder {
+
+ @Override
+ protected NodeSupport<?> getNodeSupport(ReadGraph graph, String sessionName) throws DatabaseException {
+ return JDBCSessionManager.nodeSupport(graph, sessionName);
+ }
+
+ @Override
+ protected Object getRoot(ReadGraph graph, NodeSupport<?> support, String sessionName) throws DatabaseException {
+ JDBCNodeManager manager = (JDBCNodeManager) support.manager;
+ return manager.getRoot();
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.simantics.jdbc.feature</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.pde.FeatureBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.FeatureNature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+bin.includes = feature.xml
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+ id="org.simantics.jdbc.feature"
+ label="Simantics JDBC Feature"
+ version="1.0.0.qualifier">
+
+ <description url="http://www.example.com/description">
+ [Enter Feature Description here.]
+ </description>
+
+ <copyright url="http://www.example.com/copyright">
+ [Enter Copyright Description here.]
+ </copyright>
+
+ <license url="http://www.example.com/license">
+ [Enter License Description here.]
+ </license>
+
+ <plugin
+ id="org.simantics.jdbc"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+ <plugin
+ id="org.simantics.simulator.toolkit"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+ <plugin
+ id="org.simantics.simulator.toolkit.db"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+ <plugin
+ id="org.simantics.simulator"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+ <plugin
+ id="org.simantics.jdbc.ontology"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+ <plugin
+ id="org.simantics.jdbc.simupedia.sharedlibrary"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+</feature>
<Import-Package>!sun.misc.*,*;resolution:=optional</Import-Package>
</instructions>
</artifact>
+ <artifact>
+ <id>com.impossibl.pgjdbc-ng:pgjdbc-ng:0.7.1</id>
+ <source>true</source>
+ <transitive>false</transitive>
+ </artifact>
</artifacts>
</configuration>
</execution>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
-<target name="Eclipse Oxygen" sequenceNumber="1536132639">
+<target name="Eclipse Oxygen" sequenceNumber="1536132640">
<locations>
<location includeMode="slicer" includeAllPlatforms="true" includeSource="true" includeConfigurePhase="false" type="InstallableUnit">
<unit id="com.google.guava" version="21.0.0.v20170206-1425"/>
<unit id="org.slf4j.api.source" version="1.7.25.b001"/>
<unit id="org.supercsv" version="2.4.0"/>
<unit id="org.supercsv.source" version="2.4.0"/>
+ <unit id="pgjdbc-ng" version="0.7.1"/>
+ <unit id="pgjdbc-ng.source" version="0.7.1"/>
<unit id="stax2-api" version="3.1.4"/>
<unit id="stax2-api.source" version="3.1.4"/>
<repository location="http://www.simantics.org/download/master/external-components/maven"/>
org.slf4j.api.source
org.supercsv
org.supercsv.source
+ pgjdbc-ng
+ pgjdbc-ng.source
stax2-api
stax2-api.source
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
-<target name="Simantics 1.36.0" sequenceNumber="1535957308">
+<target name="Simantics 1.36.0" sequenceNumber="1535957309">
<locations>
<location includeMode="slicer" includeAllPlatforms="true" includeSource="true" includeConfigurePhase="false" type="InstallableUnit">
<unit id="com.google.guava" version="21.0.0.v20170206-1425"/>
<unit id="org.slf4j.api.source" version="1.7.25.b001"/>
<unit id="org.supercsv" version="2.4.0"/>
<unit id="org.supercsv.source" version="2.4.0"/>
+ <unit id="pgjdbc-ng" version="0.7.1"/>
+ <unit id="pgjdbc-ng.source" version="0.7.1"/>
<unit id="stax2-api" version="3.1.4"/>
<unit id="stax2-api.source" version="3.1.4"/>
<repository location="http://www.simantics.org/download/master/external-components/maven"/>