Java tutorial
/* * Copyright (C) 2014 SETRONICA - setronica.com * This source code is available under the terms of the GNU Lesser General Public License * as published by The Open Source Initiative (OSI), either version 3 of the License, * or (at your option) any later version. * * UCS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License. */ package com.setronica.ucs.storage; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.setronica.ucs.attributes.ContentException; import com.setronica.ucs.product.IdentityType; import com.setronica.ucs.product.ProductIdentity; import com.setronica.ucs.product.identity.ProductIdentityFactory; import gnu.trove.set.TLongSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.sql.DataSource; import java.io.IOException; import java.sql.*; import java.util.HashMap; import java.util.Map; /** * User: nikolay * Date: 9/2/13 */ public class PgStructMapStorage<K, V> extends MemMapStorage<K, V> implements MapStorage<K, V> { private static final Logger L = LoggerFactory.getLogger(PgStructMapStorage.class); private DataSource ds; private Connection c; private String tableName; private PreparedStatement deletePs; private PreparedStatement updatePs; private PgStructSerialization<K> keyS; private ObjectMapper mapper = new ObjectMapper(); private Class<V> cls; public PgStructMapStorage(DataSource ds, String tableName, PgStructSerialization<K> keyS, ProductIdentityFactory identityFactory) { this.ds = ds; this.tableName = "ucs." + tableName; this.keyS = keyS; SimpleModule enumModule = new SimpleModule("MyModule") .addDeserializer(ProductIdentity.class, new MemProductIdentityDeserializer(identityFactory)) .addDeserializer(TLongSet.class, new PgCategoryStorage.TLongSetDeserializer()) .addSerializer(TLongSet.class, new PgCategoryStorage.TLongSetSerializer()); mapper.registerModule(enumModule); L.info("Create PgStructMapStorage for table: {}", tableName); } public void setProto(V proto) { this.cls = (Class<V>) proto.getClass(); } public void open() throws Exception { c = ds.getConnection(); if (c.getAutoCommit()) { c.setAutoCommit(false); } updatePs = c.prepareStatement("SET LOCAL synchronous_commit TO OFF; WITH upsert as (update " + tableName + " m set val=cast(? as json) where id=" + keyS.saveSQL() + " RETURNING m.*), tmp as (select 1) " + " insert into " + tableName + " select " + keyS.saveSQL() + ", cast(? as json) val from tmp where 0=(select count(0) from upsert); commit;"); deletePs = c.prepareStatement("SET LOCAL synchronous_commit TO OFF; delete from " + tableName + " where id=" + keyS.saveSQL() + "; commit;"); L.info("Starting populate PgStructMapStorage for table: {}", tableName); data.clear(); try (Statement stmt = c.createStatement(); ResultSet rs = stmt.executeQuery( "select " + keyS.readSQL() + ", val json_val from " + tableName + " order by id")) { while (rs.next()) { K key = keyS.restore(rs); String val = rs.getString("json_val"); if (val != null) { data.put(key, mapper.readValue(val, cls)); } } } L.info("PgStructMapStorage for table {} has size {}", tableName, data.size()); } public void close() throws SQLException { L.info("Close PgStructMapStorage for table: {}", tableName); updatePs.close(); deletePs.close(); c.close(); } @Override protected void persist(K key, V value) { try { L.trace("persist: {}/{}", key, value); String jsonVal = mapper.writeValueAsString(value); int idx = 1; updatePs.setString(idx++, jsonVal); idx = keyS.save(key, updatePs, idx); idx = keyS.save(key, updatePs, idx); updatePs.setString(idx, jsonVal); updatePs.executeUpdate(); } catch (IOException | SQLException e) { throw new RuntimeException(e); } } @Override protected void delete(K key, V value) { try { L.trace("delete: {}", key); keyS.save(key, deletePs, 1); deletePs.executeUpdate(); } catch (SQLException e) { throw new RuntimeException(e); } } public static class MemProductIdentityDeserializer extends JsonDeserializer<ProductIdentity> { private ProductIdentityFactory identityFactory; public MemProductIdentityDeserializer(ProductIdentityFactory identityFactory) { this.identityFactory = identityFactory; } @Override public ProductIdentity deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { Map<String, String> m = new HashMap<String, String>(); jsonParser.nextToken(); for (int i = 0; i < 3; i++) { String key = jsonParser.getText(); jsonParser.nextToken(); String val = jsonParser.getText(); m.put(key, val); if (jsonParser.nextToken() == JsonToken.END_OBJECT) { break; } } String type = m.get("identityType"); if (type == null) return null; try { return identityFactory.getIdentity(IdentityType.valueOf(type), m.get("value")); } catch (ContentException e) { throw new RuntimeException(e); } } } }