001package fr.ifremer.adagio.synchro.intercept.internal;
002
003/*
004 * #%L
005 * SIH-Adagio :: Synchronization
006 * $Id:$
007 * $HeadURL:$
008 * %%
009 * Copyright (C) 2012 - 2014 Ifremer
010 * %%
011 * This program is free software: you can redistribute it and/or modify
012 * it under the terms of the GNU Affero General Public License as published by
013 * the Free Software Foundation, either version 3 of the License, or
014 * (at your option) any later version.
015 * 
016 * This program is distributed in the hope that it will be useful,
017 * but WITHOUT ANY WARRANTY; without even the implied warranty of
018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
019 * GNU General Public License for more details.
020 * 
021 * You should have received a copy of the GNU Affero General Public License
022 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
023 * #L%
024 */
025
026import java.sql.SQLException;
027import java.sql.Types;
028import java.util.List;
029import java.util.Map;
030
031import oracle.sql.TIMESTAMP;
032
033import org.hibernate.dialect.Dialect;
034import org.hibernate.tool.hbm2ddl.ColumnMetadata;
035import org.hibernate.tool.hbm2ddl.TableMetadata;
036
037import com.google.common.base.Preconditions;
038import com.google.common.collect.Lists;
039import com.google.common.collect.Maps;
040
041import fr.ifremer.adagio.synchro.dao.SynchroTableDao;
042import fr.ifremer.adagio.synchro.intercept.SynchroInterceptorBase;
043import fr.ifremer.adagio.synchro.intercept.SynchroWriteBuffer;
044import fr.ifremer.adagio.synchro.meta.SynchroDatabaseMetadata;
045import fr.ifremer.adagio.synchro.meta.SynchroTableMetadata;
046import fr.ifremer.adagio.synchro.service.SynchroContext;
047
048/**
049 * Workaround need for Oracle timestamp serialization
050 * If ojdbc not found in classpath, do not try to cast to TIMESTAMP
051 * 
052 * @author Benoit Lavenier <benoit.lavenier@e-is.pro>
053 * @since
054 * 
055 */
056public class OracleInterceptor extends SynchroInterceptorBase {
057
058    private Map<TableMetadata, int[]> columnIndexesByTable = Maps.newHashMap();
059
060    private SynchroTableDao lastDao = null;
061
062    private int[] lastIndexes = null;
063
064    @Override
065    public boolean apply(SynchroDatabaseMetadata meta, TableMetadata table) {
066        boolean isOracleDialect = meta.getDialect().getClass().getName().contains("Oracle");
067        if (!isOracleDialect) {
068            return false;
069        }
070
071        Map<String, ColumnMetadata> columns = SynchroTableMetadata.getColumns(table);
072        List<Integer> columnIndexesList = Lists.newArrayList();
073        int index = 0;
074        for (ColumnMetadata column : columns.values()) {
075            if (column.getTypeCode() == Types.DATE
076                    || column.getTypeCode() == Types.TIMESTAMP) {
077                columnIndexesList.add(index);
078            }
079            index++;
080        }
081
082        if (columnIndexesList.isEmpty()) {
083            return false;
084        }
085
086        int[] columnIndexes = getColumnIndexes(table);
087        if (columnIndexes == null) {
088            return false;
089        }
090
091        columnIndexesByTable.put(table, columnIndexes);
092
093        return true;
094    }
095
096    @Override
097    public boolean enableOnRead() {
098        return true;
099    }
100
101    @Override
102    protected String doCreateSelectQuery(SynchroTableMetadata table, String queryName, String sql) {
103        return sql;
104    }
105
106    @Override
107    protected void doOnRead(Object[] data, SynchroTableDao dao) throws SQLException {
108        if (dao != lastDao) {
109            lastIndexes = getColumnMapIndexes(dao);
110            lastDao = dao;
111        }
112        for (int index : lastIndexes) {
113            Object value = data[index];
114            if (value != null && value instanceof TIMESTAMP) {
115                data[index] = ((TIMESTAMP) value).timestampValue();
116            }
117        }
118    }
119
120    @Override
121    public boolean enableOnWrite() {
122        return true;
123    }
124
125    @Override
126    protected void doOnWrite(Object[] data, SynchroTableDao dao, SynchroWriteBuffer buffer) throws SQLException {
127        if (dao != lastDao) {
128            lastIndexes = getColumnMapIndexes(dao);
129            lastDao = dao;
130        }
131        for (int index : lastIndexes) {
132            Object value = data[index];
133            if (value != null && value instanceof TIMESTAMP) {
134                data[index] = ((TIMESTAMP) value).timestampValue();
135            }
136        }
137    }
138
139    protected int[] getColumnMapIndexes(SynchroTableDao dao) {
140        TableMetadata table = dao.getTable().getDelegate();
141        int[] columnIndexes = columnIndexesByTable.get(table);
142        if (columnIndexes == null) {
143            columnIndexes = getColumnIndexes(table);
144            columnIndexesByTable.put(table, columnIndexes);
145        }
146        return columnIndexes;
147    }
148
149    protected int[] getColumnIndexes(TableMetadata table) {
150        Map<String, ColumnMetadata> columns = SynchroTableMetadata.getColumns(table);
151        if (columns == null) {
152            return null;
153        }
154
155        List<Integer> columnIndexesList = Lists.newArrayList();
156        int index = 0;
157        for (ColumnMetadata column : columns.values()) {
158            if (column.getTypeCode() == Types.DATE
159                    || column.getTypeCode() == Types.TIMESTAMP) {
160                columnIndexesList.add(index);
161            }
162            index++;
163        }
164
165        if (columnIndexesList.isEmpty()) {
166            return null;
167        }
168
169        int[] columnIndexes = new int[columnIndexesList.size()];
170        index = 0;
171        for (Integer columnIndex : columnIndexesList) {
172            columnIndexes[index] = columnIndex;
173        }
174
175        return columnIndexes;
176    }
177}