/* * Copyright 2013 Robert von Burg <eitch@eitchnet.ch> * * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 * * 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 exporders or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package li.strolch.persistence.postgresql; import java.io.IOException; import java.io.InputStream; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLXML; import java.sql.Timestamp; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.sax.SAXResult; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import li.strolch.model.Order; import li.strolch.model.Tags; import li.strolch.model.query.OrderQuery; import li.strolch.model.xml.OrderToSaxVisitor; import li.strolch.model.xml.SimpleStrolchElementListener; import li.strolch.model.xml.XmlModelSaxReader; import li.strolch.persistence.api.OrderDao; import li.strolch.persistence.api.StrolchPersistenceException; @SuppressWarnings("nls") public class PostgreSqlOrderDao extends PostgresqlDao<Order> implements OrderDao { public static final String ORDERS = "orders"; public PostgreSqlOrderDao(PostgreSqlStrolchTransaction tx) { super(tx); } @Override protected String getClassName() { return Tags.ORDER; } @Override protected String getTableName() { return ORDERS; } @Override protected Order parseFromXml(String id, String type, SQLXML sqlxml) { SimpleStrolchElementListener listener = new SimpleStrolchElementListener(); try (InputStream binaryStream = sqlxml.getBinaryStream()) { SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); parser.parse(binaryStream, new XmlModelSaxReader(listener)); } catch (SQLException | IOException | SAXException | ParserConfigurationException e) { throw new StrolchPersistenceException(MessageFormat.format( "Failed to extract Order from sqlxml value for {0} / {1}", id, type), e); } if (listener.getOrders().size() == 0) throw new StrolchPersistenceException(MessageFormat.format( "No Orders parsed from sqlxml value for {0} / {1}", id, type)); if (listener.getOrders().size() > 1) throw new StrolchPersistenceException(MessageFormat.format( "Multiple Orders parsed from sqlxml value for {0} / {1}", id, type)); return listener.getOrders().get(0); } protected SQLXML createSqlXml(Order order, PreparedStatement preparedStatement) throws SQLException, SAXException { SQLXML sqlxml = tx().getConnection().createSQLXML(); SAXResult saxResult = sqlxml.setResult(SAXResult.class); ContentHandler contentHandler = saxResult.getHandler(); contentHandler.startDocument(); new OrderToSaxVisitor(contentHandler).visit(order); contentHandler.endDocument(); return sqlxml; } @Override protected void internalSave(final Order order) { String sql = "insert into " + getTableName() + " (id, name, type, state, date, asxml) values (?, ?, ?, ?::order_state, ?, ?)"; try (PreparedStatement preparedStatement = tx().getConnection().prepareStatement(sql)) { preparedStatement.setString(1, order.getId()); preparedStatement.setString(2, order.getName()); preparedStatement.setString(3, order.getType()); preparedStatement.setString(4, order.getState().name()); preparedStatement.setTimestamp(5, new Timestamp(order.getDate().getTime()), Calendar.getInstance()); SQLXML sqlxml = createSqlXml(order, preparedStatement); preparedStatement.setSQLXML(6, sqlxml); try { int modCount = preparedStatement.executeUpdate(); if (modCount != 1) { String msg = "Expected to save 1 element with id {0} but SQL statement modified {1} elements!"; msg = MessageFormat.format(msg, order.getId(), modCount); throw new StrolchPersistenceException(msg); } } finally { sqlxml.free(); } } catch (SQLException | SAXException e) { throw new StrolchPersistenceException(MessageFormat.format("Failed to insert Order {0} due to {1}", order.getLocator(), e.getLocalizedMessage()), e); } } @Override protected void internalUpdate(final Order order) { String sql = "update " + getTableName() + " set name = ?, type = ?, state = ?::order_state, date = ?, asxml = ? where id = ? "; try (PreparedStatement preparedStatement = tx().getConnection().prepareStatement(sql)) { preparedStatement.setString(1, order.getName()); preparedStatement.setString(2, order.getType()); preparedStatement.setString(3, order.getState().name()); preparedStatement.setTimestamp(4, new Timestamp(order.getDate().getTime()), Calendar.getInstance()); preparedStatement.setString(6, order.getId()); SQLXML sqlxml = createSqlXml(order, preparedStatement); preparedStatement.setSQLXML(5, sqlxml); try { int modCount = preparedStatement.executeUpdate(); if (modCount != 1) { String msg = "Expected to update 1 element with id {0} but SQL statement modified {1} elements!"; msg = MessageFormat.format(msg, order.getId(), modCount); throw new StrolchPersistenceException(msg); } } finally { sqlxml.free(); } } catch (SQLException | SAXException e) { throw new StrolchPersistenceException(MessageFormat.format("Failed to update Order {0} due to {1}", order.getLocator(), e.getLocalizedMessage()), e); } } @Override public <U> List<U> doQuery(OrderQuery<U> query) { PostgreSqlOrderQueryVisitor queryVisitor = new PostgreSqlOrderQueryVisitor("id, asxml"); query.accept(queryVisitor); queryVisitor.validate(); List<U> list = new ArrayList<>(); String sql = queryVisitor.getSql(); try (PreparedStatement ps = tx().getConnection().prepareStatement(sql)) { queryVisitor.setValues(ps); try (ResultSet result = ps.executeQuery()) { while (result.next()) { String id = result.getString("id"); SQLXML sqlxml = result.getSQLXML("asxml"); Order t = parseFromXml(id, queryVisitor.getType(), sqlxml); list.add(query.getOrderVisitor().visit(t)); } } } catch (SQLException e) { throw new StrolchPersistenceException("Failed to perform query due to: " + e.getMessage(), e); } return list; } }