/****************************************************************************** * * Copyright 2014 Paphus Solutions Inc. * * Licensed under the Eclipse Public License, Version 1.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ package org.botlibre.knowledge.database; import java.util.HashMap; import java.util.Map; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.Query; import javax.persistence.SynchronizationType; import org.botlibre.api.knowledge.Data; import org.botlibre.api.knowledge.MemoryStorageException; import org.botlibre.api.knowledge.Network; import org.botlibre.api.knowledge.Relationship; import org.botlibre.api.knowledge.Vertex; import org.botlibre.knowledge.BasicVertex; import org.botlibre.knowledge.Primitive; import org.eclipse.persistence.config.QueryHints; import org.eclipse.persistence.internal.jpa.EntityManagerImpl; import org.eclipse.persistence.sessions.server.ServerSession; /** * Network using JPA to access a PostgresQL database. * This is used for read-only access, and is shared by all objects in the cache. */ public class DatabaseReadOnlyNetwork extends DatabaseNetwork { static Map<String, Object> properties; static { properties = new HashMap<String, Object>(); properties.put(QueryHints.READ_ONLY, true); } public DatabaseReadOnlyNetwork(EntityManager entityManager, boolean isShortTerm) { super(new EntityManagerImpl(entityManager.unwrap(ServerSession.class), SynchronizationType.UNSYNCHRONIZED), isShortTerm); ServerSession server = entityManager.unwrap(ServerSession.class); if (!server.getProperties().containsKey("network")) { server.setProperty("network", this); } } public boolean isReadOnly() { return true; } protected void addRelationship(Relationship relationship) { throwReadOnly(); } protected void throwReadOnly() { MemoryStorageException exception = new MemoryStorageException("Network is read-only."); exception.printStackTrace(); throw exception; } /** * Resume the network after a save. * Keep the MAX_SIZE number of most conscious vertices in memory. */ public void resume() { throwReadOnly(); } /** * Execute and commit the native query. */ public int executeNativeQuery(String sql) { throwReadOnly(); return 0; } /** * Execute and commit the update query. */ public int executeQuery(String jpql) { throwReadOnly(); return 0; } /** * Commit memory to the database. */ public void save() { throwReadOnly(); } /** * Add the existing vertex to the network. * Used to load an existing vertex, createVertex must be used to create a new one. */ public synchronized void addVertex(Vertex vertex) { throwReadOnly(); } /** * Find the exiting vertex, or create a temporary one for primitives. */ @SuppressWarnings("rawtypes") public synchronized Vertex createVertex(Object data) { if ((data instanceof String) && ((String)data).length() > MAX_TEXT) { data = ((String)data).substring(0, MAX_TEXT); } if (data instanceof Class) { data = new Primitive(((Class)data).getName()); } Vertex vertex = findByData(data); if (vertex != null) { return vertex; } if (data instanceof Primitive) { vertex = new BasicVertex(); vertex.setData(data); vertex.setNetwork(this); return vertex; } throwReadOnly(); return null; } /** * Save the property setting to the current transaction. */ public void saveProperty(String propertyName, String value, boolean startup) { throwReadOnly(); } /** * Remove the property setting to the current transaction. */ public void removeProperty(String propertyName) { throwReadOnly(); } /** * Remove the vertex from the network. * Note that the vertex must be no longer referenced by any other vertex in the network. */ public void removeVertex(Vertex vertex) { throwReadOnly(); } /** * Remove the vertex and all references to it from the network. */ public void removeVertexAndReferences(Vertex vertex) { throwReadOnly(); } /** * Remove the relationship from the network. * Note that the relationship must be no longer referenced by any other vertex in the network. */ public void removeRelationship(Relationship relationship) { throwReadOnly(); } public void setHints(Query query) { query.setHint(QueryHints.READ_ONLY, true); } /** * Return the vertex with the given data. */ public synchronized Vertex findByData(Object data) { if (data == null) { return null; } Vertex vertex = this.verticiesByData.get(data); if (vertex != null) { return vertex; } Query query = getEntityManager().createNamedQuery("findVertexByData"); query.setHint(QueryHints.READ_ONLY, true); query.setParameter("data", BasicVertex.convertDataValue(data)); query.setParameter("type", BasicVertex.convertDataType(data)); try { vertex = (Vertex)query.getSingleResult(); if (this.verticiesByData.size() < MAX_SIZE) { this.verticiesByData.put(vertex.getData(), vertex); } return vertex; } catch (NoResultException notFound) { return null; } } /** * Return the vertex with the given name. */ public synchronized Vertex findById(Number id) { if (id == null) { return null; } return getEntityManager().find(BasicVertex.class, id, properties); } /** * Return the lob data. */ public synchronized Data findData(Data data) { if (data == null) { return null; } return getEntityManager().find(data.getClass(), data.getId(), properties); } /** * Merge the vertices and relations of the network into this network. */ public synchronized void merge(Network network) { throwReadOnly(); } }