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

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

adding trasnactional, refactoring and fixing bugs in updated annotations, removing try-catch from resource methods (The Greek's advice)

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