source: DASISH/t5.6/backend/annotator-backend/trunk/annotator-backend/src/main/java/eu/dasish/annotation/backend/dao/impl/JdbcAnnotationDao.java @ 4183

Last change on this file since 4183 was 4183, checked in by olhsha, 10 years ago

fixing HSQL/Postgres discrepance problem when setting an current_time date in UTC as default (translation added for Unit test DB and actual Postgres DB is updated so the defaults is set implicitely (no need to send it via the sql request).

File size: 22.2 KB
Line 
1/*
2 * Copyright (C) 2013 DASISH
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17 */
18package eu.dasish.annotation.backend.dao.impl;
19
20import eu.dasish.annotation.backend.Helpers;
21import eu.dasish.annotation.backend.dao.AnnotationDao;
22import eu.dasish.annotation.schema.Annotation;
23import eu.dasish.annotation.schema.AnnotationBody;
24import eu.dasish.annotation.schema.AnnotationBody.TextBody;
25import eu.dasish.annotation.schema.AnnotationBody.XmlBody;
26import eu.dasish.annotation.schema.AnnotationInfo;
27import eu.dasish.annotation.schema.Permission;
28import java.lang.String;
29import java.sql.ResultSet;
30import java.sql.SQLException;
31import java.sql.Timestamp;
32import java.util.ArrayList;
33import java.util.HashMap;
34import java.util.List;
35import java.util.Map;
36import java.util.UUID;
37import javax.sql.DataSource;
38import javax.xml.datatype.DatatypeConfigurationException;
39import org.springframework.jdbc.core.RowMapper;
40
41/**
42 * Created on : Jun 27, 2013, 10:30:52 AM
43 *
44 * @author Peter Withers <peter.withers@mpi.nl>
45 */
46public class JdbcAnnotationDao extends JdbcResourceDao implements AnnotationDao {
47
48    public JdbcAnnotationDao(DataSource dataSource) {
49        setDataSource(dataSource);
50        internalIdName = annotation_id;
51        resourceTableName = annotationTableName;
52
53    }
54
55    @Override
56    public void setServiceURI(String serviceURI) {
57        _serviceURI = serviceURI;
58    }
59
60    ///////////// GETTERS /////////////
61    @Override
62    public List<Number> retrieveTargetIDs(Number annotationID) {
63        if (annotationID != null) {
64            StringBuilder sql = new StringBuilder("SELECT DISTINCT ");
65            sql.append(target_id).append(" FROM ").append(annotationsTargetsTableName).append(" WHERE ").append(annotation_id).append("= ?");
66            return getSimpleJdbcTemplate().query(sql.toString(), TargetIDRowMapper, annotationID);
67        } else {
68            return null;
69        }
70    }
71
72    ///////////////////////////////////////////////////////////////////
73    @Override
74    public List<Map<Number, String>> getPermissions(Number annotationID) {
75        if (annotationID == null) {
76            return null;
77        }
78        StringBuilder sql = new StringBuilder("SELECT ");
79        sql.append(principal_id).append(",").append(permission).append(" FROM ").append(permissionsTableName).append(" WHERE ").append(annotation_id).append("  = ?");
80        return getSimpleJdbcTemplate().query(sql.toString(), principalsPermissionsRowMapper, annotationID);
81    }
82    private final RowMapper<Map<Number, String>> principalsPermissionsRowMapper = new RowMapper<Map<Number, String>>() {
83        @Override
84        public Map<Number, String> mapRow(ResultSet rs, int rowNumber) throws SQLException {
85            Map<Number, String> result = new HashMap<Number, String>();
86            result.put(rs.getInt(principal_id), rs.getString(permission));
87            return result;
88        }
89    };
90
91    @Override
92    public Permission getPermission(Number annotationID, Number userID) {
93        if (annotationID == null || userID == null) {
94            return null;
95        }
96        StringBuilder sql = new StringBuilder("SELECT ");
97        sql.append(permission).append(" FROM ").append(permissionsTableName).append(" WHERE ").
98                append(annotation_id).append("  = ").append(annotationID.toString()).append(" AND ").
99                append(principal_id).append("  = ").append(userID.toString()).append(" LIMIT 1");
100        List<Permission> result = getSimpleJdbcTemplate().query(sql.toString(), permissionRowMapper);
101        if (result == null) {
102            return null;
103        }
104        if (result.isEmpty()) {
105            return null;
106        }
107        return result.get(0);
108    }
109    private final RowMapper<Permission> permissionRowMapper = new RowMapper<Permission>() {
110        @Override
111        public Permission mapRow(ResultSet rs, int rowNumber) throws SQLException {
112            return Permission.fromValue(rs.getString(permission));
113        }
114    };
115
116    @Override
117    public List<Number> getAnnotationIDsForUserWithPermission(Number userID, String permissionString) {
118        if (userID == null || permissionString == null) {
119            return null;
120        }
121        StringBuilder sql = new StringBuilder("SELECT ");
122        sql.append(annotation_id).append(" FROM ").append(permissionsTableName).append(" WHERE ").
123                append(principal_id).append("  = ").append(userID.toString()).append(" AND ").
124                append(permission).append("  = ?");;
125        return getSimpleJdbcTemplate().query(sql.toString(), internalIDRowMapper, permissionString);
126    }
127
128    ////////////////////////////////////////////////////////////////////////
129    @Override
130    public List<Number> getFilteredAnnotationIDs(List<Number> annotationIDs, String text, String namespace, Number ownerID, Timestamp after, Timestamp before) {
131
132        StringBuilder sql = new StringBuilder("SELECT DISTINCT ");
133        sql.append(annotation_id).append(" FROM ").append(annotationTableName).append(" WHERE TRUE ");
134        Map<String, Object> params = new HashMap<String, Object>();
135
136        if (annotationIDs == null) {
137            return null;
138        } else {
139            if (annotationIDs.isEmpty()) {
140                return new ArrayList<Number>();
141            }
142        }
143
144        String values = makeListOfValues(annotationIDs);
145        sql.append(" AND ").append(annotation_id).append(" IN ").append(values);
146
147
148        if (ownerID != null) {
149            sql.append(" AND ").append(owner_id).append(" = :owner ");
150            params.put("owner", ownerID);
151        }
152
153        if (after != null) {
154            sql.append(" AND ").append(last_modified).append("  > :after");
155            params.put("after", after);
156        }
157
158        if (before != null) {
159            sql.append(" AND ").append(last_modified).append("  < :before");
160            params.put("before", before);
161        }
162
163        if (text != null) {
164            sql.append(" AND ").append(body_text).append("  LIKE '%").append(text).append("%'");
165        }
166
167        return getSimpleJdbcTemplate().query(sql.toString(), internalIDRowMapper, params);
168    }
169
170    //////////////////////////////
171    @Override
172    public List<Number> retrieveAnnotationList(List<Number> TargetIDs) {
173        if (TargetIDs == null) {
174            return null;
175        }
176        if (TargetIDs.isEmpty()) {
177            return new ArrayList<Number>();
178        }
179        String values = makeListOfValues(TargetIDs);
180        StringBuilder query = new StringBuilder("SELECT DISTINCT ");
181        query.append(annotation_id).append(" FROM ").append(annotationsTargetsTableName).append(" WHERE ").append(target_id).append(" IN ");
182        query.append(values);
183        return getSimpleJdbcTemplate().query(query.toString(), internalIDRowMapper);
184    }
185
186    @Override
187    public Map<AnnotationInfo, Number> getAnnotationInfoWithoutTargets(Number annotationID) {
188        if (annotationID == null) {
189            return null;
190        }
191        StringBuilder sql = new StringBuilder("SELECT  ");
192        sql.append(annotationStar).append(" FROM ").append(annotationTableName).append(" WHERE ").append(annotation_id).append("  = ? ");
193        List<Map<AnnotationInfo, Number>> result = getSimpleJdbcTemplate().query(sql.toString(), annotationInfoRowMapper, annotationID);
194        if (result == null) {
195            return null;
196        }
197        if (result.isEmpty()) {
198            return null;
199        }
200
201        return result.get(0);
202    }
203    private final RowMapper<Map<AnnotationInfo, Number>> annotationInfoRowMapper = new RowMapper<Map<AnnotationInfo, Number>>() {
204        @Override
205        public Map<AnnotationInfo, Number> mapRow(ResultSet rs, int rowNumber) throws SQLException {
206            Map<AnnotationInfo, Number> result = new HashMap<AnnotationInfo, Number>();
207            AnnotationInfo annotationInfo = new AnnotationInfo();
208            annotationInfo.setRef(externalIDtoURI(rs.getString(external_id)));
209            annotationInfo.setHeadline(rs.getString(headline));
210            annotationInfo.setLastModified(timeStampToXMLGregorianCalendar(rs));
211            result.put(annotationInfo, rs.getInt(owner_id));
212            return result;
213        }
214    };
215
216    /////////////////////////////////////////////////
217    /**
218     *
219     * @param annotationIDs
220     * @return list of annotation references corresponding to the annotation-ids
221     * from the input list if the input list is null or empty (zero elements)
222     * returns an empty list there may be annotationIDs which are not in the DB
223     * (so that's why we need this method).
224     */
225    @Override
226    public List<String> getAnnotationREFs(List<Number> annotationIDs) {
227        if (annotationIDs == null) {
228            return null;
229        }
230        if (annotationIDs.isEmpty()) {
231            return (new ArrayList<String>());
232        }
233
234        String values = makeListOfValues(annotationIDs);
235        StringBuilder sql = new StringBuilder("SELECT DISTINCT ");
236        sql.append(external_id).append(" FROM ").append(annotationTableName).append(" WHERE ").append(annotationAnnotation_id).append("  IN ").append(values);
237        return getSimpleJdbcTemplate().query(sql.toString(), annotationREFRowMapper);
238    }
239    private final RowMapper<String> annotationREFRowMapper = new RowMapper<String>() {
240        @Override
241        public String mapRow(ResultSet rs, int rowNumber) throws SQLException {
242            return externalIDtoURI(rs.getString(external_id));
243        }
244    };
245
246    //////////////////////////////////////////////////////////////////////////
247    @Override
248    public Map<Annotation, Number> getAnnotationWithoutTargetsAndPermissions(Number annotationID) {
249        if (annotationID == null) {
250            return null;
251        }
252        StringBuilder sql = new StringBuilder("SELECT ");
253        sql.append(annotationStar).append(" FROM ").append(annotationTableName).append(" WHERE ").append(annotationAnnotation_id).append("= ? LIMIT  1");
254        List<Map<Annotation, Number>> respond = getSimpleJdbcTemplate().query(sql.toString(), annotationRowMapper, annotationID);
255        return (respond.isEmpty() ? null : respond.get(0));
256    }
257    private final RowMapper<Map<Annotation, Number>> annotationRowMapper = new RowMapper<Map<Annotation, Number>>() {
258        @Override
259        public Map<Annotation, Number> mapRow(ResultSet rs, int rowNumber) throws SQLException {
260            Map<Annotation, Number> result = new HashMap<Annotation, Number>();
261
262            Annotation annotation = new Annotation();
263            result.put(annotation, rs.getInt(owner_id));
264
265            annotation.setHeadline(rs.getString(headline));
266
267            AnnotationBody body = new AnnotationBody();
268            if (rs.getBoolean(is_xml)) {
269                body.setTextBody(null);
270                XmlBody xmlBody = new XmlBody();
271                xmlBody.setMimeType(rs.getString(body_mimetype));
272                xmlBody.setAny(Helpers.stringToElement(rs.getString(body_text)));
273                body.setXmlBody(xmlBody);
274            } else {
275                body.setXmlBody(null);
276                TextBody textBody = new TextBody();
277                textBody.setMimeType(rs.getString(body_mimetype));
278                textBody.setValue(rs.getString(body_text));
279                body.setTextBody(textBody);
280            }
281            annotation.setBody(body);
282
283            annotation.setTargets(null);
284            annotation.setURI(externalIDtoURI(rs.getString(external_id)));
285            annotation.setLastModified(timeStampToXMLGregorianCalendar(rs));
286            return result;
287        }
288    };
289
290    /////////////////////////////
291    @Override
292    public boolean annotationIsInUse(Number annotationID) {
293        StringBuilder sqlNotebooks = new StringBuilder("SELECT ");
294        sqlNotebooks.append(notebook_id).append(" FROM ").append(notebooksAnnotationsTableName).append(" WHERE ").append(annotation_id).append("= ? LIMIT 1");
295        List<Number> resultNotebooks = getSimpleJdbcTemplate().query(sqlNotebooks.toString(), notebookIDRowMapper, annotationID);
296        if (resultNotebooks.size() > 0) {
297            return true;
298        }
299
300        StringBuilder sqlTargets = new StringBuilder("SELECT ");
301        sqlTargets.append(target_id).append(" FROM ").append(annotationsTargetsTableName).append(" WHERE ").append(annotation_id).append("= ? LIMIT 1");
302        List<Number> resultTargets = getSimpleJdbcTemplate().query(sqlTargets.toString(), TargetIDRowMapper, annotationID);
303        if (resultTargets.size() > 0) {
304            return true;
305        }
306
307        StringBuilder sqlPermissions = new StringBuilder("SELECT ");
308        sqlPermissions.append(principal_id).append(" FROM ").append(permissionsTableName).append(" WHERE ").append(annotation_id).append("= ? LIMIT 1");
309        List<Number> resultPermissions = getSimpleJdbcTemplate().query(sqlPermissions.toString(), principalIDRowMapper, annotationID);
310        return (resultPermissions.size() > 0);
311    }
312
313    //////////// UPDATERS /////////////
314    @Override
315    public int updateAnnotationBodyText(Number annotationID, String text) {
316        StringBuilder sql = new StringBuilder("UPDATE ");
317        sql.append(annotationTableName).append(" SET ").
318                append(last_modified).append("=  default,").
319                append(body_text).append("= '").append(text).
320                append("' WHERE ").append(annotation_id).append("= ?");
321        int affectedRows = getSimpleJdbcTemplate().update(sql.toString(), annotationID);
322        return affectedRows;
323    }
324
325    @Override
326    public int updateAnnotationBody(Number annotationID, AnnotationBody annotationBody) {
327        String[] body = retrieveBodyComponents(annotationBody);
328        Map<String, Object> params = new HashMap<String, Object>();
329        params.put("annotationID", annotation_id);
330        params.put("bodyText", body[0]);
331        params.put("bodyMimeType", body[1]);
332        params.put("isXml", annotationBody.getXmlBody() != null);
333
334        StringBuilder sql = new StringBuilder("UPDATE ");
335        sql.append(annotationTableName).append(" SET ").
336                append(last_modified).append("=  default,").
337                append(body_text).append("= :bodyText, ").
338                append(body_mimetype).append("= :bodyMimeType, ").
339                append(is_xml).append("= :isXml").
340                append("' WHERE ").append(annotation_id).append("= :annotationID");
341        int affectedRows = getSimpleJdbcTemplate().update(sql.toString(), annotationID);
342        return affectedRows;
343    }
344
345    // TODO Unit test
346    @Override
347    public int updateAnnotation(Annotation annotation, Number ownerID) {
348
349        String[] body = retrieveBodyComponents(annotation.getBody());
350        String externalID = stringURItoExternalID(annotation.getURI());
351        Map<String, Object> params = new HashMap<String, Object>();
352        params.put("bodyText", body[0]);
353        params.put("bodyMimeType", body[1]);
354        params.put("headline", annotation.getHeadline());
355        params.put("isXml", annotation.getBody().getXmlBody() != null);
356        params.put("externalID", externalID);
357
358
359        StringBuilder sql = new StringBuilder("UPDATE ");
360        sql.append(annotationTableName).append(" SET ").
361                append(body_text).append("=  :bodyText ,").
362                append(body_mimetype).append("= :bodyMimeType ,").
363                append(headline).append("=  :headline ,").
364                append(last_modified).append("=  default,").
365                append(is_xml).append("= :isXml").
366                append(" WHERE ").append(external_id).append("= :externalID");
367        int affectedRows = getSimpleJdbcTemplate().update(sql.toString(), params);
368        return affectedRows;
369    }
370
371    @Override
372    public int updateAnnotationPrincipalPermission(Number annotationID, Number userID, Permission permission) {
373
374        Map<String, Object> params = new HashMap<String, Object>();
375        params.put("permission", permission.value());
376        params.put("annotationID", annotation_id);
377        params.put("principalID", principal_id);
378
379        StringBuilder sql = new StringBuilder("UPDATE ");
380        sql.append(permissionsTableName).append(" SET ").
381                append(this.permission).append("= :permission").
382                append(" WHERE ").append(annotation_id).append("= : annotationID").
383                append(" AND ").append(principal_id).append("= :principalID");
384        return getSimpleJdbcTemplate().update(sql.toString(), params);
385    }
386
387    //////////// ADDERS ////////////////////////
388    @Override
389    public Number addAnnotation(Annotation annotation, Number ownerID) {
390
391        String[] body = retrieveBodyComponents(annotation.getBody());
392
393        // generate a new annotation ID
394        UUID externalID = UUID.randomUUID();
395        Map<String, Object> params = new HashMap<String, Object>();
396        params.put("externalId", externalID.toString());
397        params.put("ownerId", ownerID);
398        params.put("headline", annotation.getHeadline());
399        params.put("bodyText", body[0]);
400        params.put("bodyMimeType", body[1]);
401        params.put("isXml", annotation.getBody().getXmlBody() != null);
402
403        StringBuilder sql = new StringBuilder("INSERT INTO ");
404        sql.append(annotationTableName).append("(").append(external_id).append(",").append(owner_id);
405        sql.append(",").append(headline).append(",").append(body_text).append(",").append(body_mimetype).append(",").append(is_xml).
406                append(" ) VALUES (:externalId, :ownerId, :headline, :bodyText, :bodyMimeType, :isXml)");
407        int affectedRows = getSimpleJdbcTemplate().update(sql.toString(), params);
408        return ((affectedRows > 0) ? getInternalID(externalID) : null);
409    }
410
411    //////////////////////////////////////////////////////////////////////////////////
412    @Override
413    public int addAnnotationTarget(Number annotationID, Number targetID) {
414        Map<String, Object> paramsAnnotationsTargets = new HashMap<String, Object>();
415        paramsAnnotationsTargets.put("annotationId", annotationID);
416        paramsAnnotationsTargets.put("targetId", targetID);
417        StringBuilder sqlAnnotationsTargets = new StringBuilder("INSERT INTO ");
418        sqlAnnotationsTargets.append(annotationsTargetsTableName).append("(").append(annotation_id).append(",").append(target_id).append(" ) VALUES (:annotationId, :targetId)");
419        return getSimpleJdbcTemplate().update(sqlAnnotationsTargets.toString(), paramsAnnotationsTargets);
420    }
421
422    /////////////////////////////////////////////////////////////////////////////////////////
423    @Override
424    public int addAnnotationPrincipalPermission(Number annotationID, Number userID, Permission permission) {
425        Map<String, Object> paramsPermissions = new HashMap<String, Object>();
426        paramsPermissions.put("annotationId", annotationID);
427        paramsPermissions.put("principalId", userID);
428        paramsPermissions.put("status", permission.value());
429        StringBuilder sqlUpdatePermissionTable = new StringBuilder("INSERT INTO ");
430        sqlUpdatePermissionTable.append(permissionsTableName).append(" (").append(annotation_id).append(",").append(principal_id).append(",").append(this.permission).append(") VALUES (:annotationId, :principalId, :status)");
431        final int affectedPermissions = getSimpleJdbcTemplate().update(sqlUpdatePermissionTable.toString(), paramsPermissions);
432        return affectedPermissions;
433    }
434
435    //////////////////////////////////////////////////////////////////////////////////
436    /////////////////// DELETERS //////////////////////////
437    @Override
438    public int deleteAnnotation(Number annotationID) {
439        if (annotationID != null) {
440            if (annotationIsInUse(annotationID)) {
441                return 0;
442            }
443            StringBuilder sqlAnnotation = new StringBuilder("DELETE FROM ");
444            sqlAnnotation.append(annotationTableName).append(" where ").append(annotation_id).append(" = ?");
445            return (getSimpleJdbcTemplate().update(sqlAnnotation.toString(), annotationID));
446        } else {
447            return 0;
448        }
449    }
450
451    @Override
452    public int deleteAllAnnotationTarget(Number annotationID) {
453        if (annotationID != null) {
454            StringBuilder sqlTargetTargets = new StringBuilder("DELETE FROM ");
455            sqlTargetTargets.append(annotationsTargetsTableName).append(" WHERE ").append(annotation_id).append(" = ?");
456            return getSimpleJdbcTemplate().update(sqlTargetTargets.toString(), annotationID); // # removed "annotations_target_Targets" rows
457        } else {
458            return 0;
459        }
460    }
461
462    //////////////////////////////////////////////////////
463    @Override
464    public int deleteAnnotationPrincipalPermissions(Number annotationID) {
465        if (annotationID != null) {
466            StringBuilder sqlPermissions = new StringBuilder("DELETE FROM ");
467            sqlPermissions.append(permissionsTableName).append(" WHERE ").append(annotation_id).append(" = ?");
468            return getSimpleJdbcTemplate().update(sqlPermissions.toString(), annotationID); // removed "permission" rows
469        } else {
470            return 0;
471        }
472
473    }
474
475    /////////////// helpers //////////////////
476    private String[] retrieveBodyComponents(AnnotationBody annotationBody) {
477        boolean body_is_xml = annotationBody.getXmlBody() != null;
478        String[] result = new String[2];
479        if (body_is_xml) {
480            result[0] = Helpers.elementToString(annotationBody.getXmlBody().getAny());
481            result[1] = annotationBody.getXmlBody().getMimeType();
482        } else {
483            TextBody textBody = annotationBody.getTextBody();
484            if (textBody != null) {
485                result[0] = textBody.getValue();
486                result[1] = textBody.getMimeType();
487            } else {
488                logger.error("Ill-formed body: both options, xml-body and text-body, are set to null. ");
489                return null;
490            }
491        }
492        return result;
493    }
494}
Note: See TracBrowser for help on using the repository browser.