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

Last change on this file since 3365 was 3365, checked in by olhsha, 11 years ago

getting the list of annotation IDs, where annotations are filtered by link, text, etc. So far body is considered as a text (got from xmls list of elements, vis get(0)). NOT TESTED yet!

File size: 15.9 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.backend.dao.NotebookDao;
23import eu.dasish.annotation.backend.dao.PermissionsDao;
24import eu.dasish.annotation.backend.dao.SourceDao;
25import eu.dasish.annotation.backend.dao.UserDao;
26import eu.dasish.annotation.backend.identifiers.AnnotationIdentifier;
27import eu.dasish.annotation.backend.identifiers.UserIdentifier;
28import eu.dasish.annotation.schema.Annotation;
29import eu.dasish.annotation.schema.AnnotationBody;
30import eu.dasish.annotation.schema.AnnotationInfo;
31import eu.dasish.annotation.schema.NewOrExistingSourceInfo;
32import eu.dasish.annotation.schema.NewOrExistingSourceInfos;
33import eu.dasish.annotation.schema.NewSourceInfo;
34import eu.dasish.annotation.schema.ResourceREF;
35import eu.dasish.annotation.schema.SourceInfo;
36import java.sql.ResultSet;
37import java.sql.SQLException;
38import java.sql.Timestamp;
39import java.util.ArrayList;
40import java.util.HashMap;
41import java.util.List;
42import java.util.Map;
43import javax.sql.DataSource;
44import javax.xml.datatype.DatatypeConfigurationException;
45import org.springframework.beans.factory.annotation.Autowired;
46import org.springframework.dao.DataAccessException;
47import org.springframework.jdbc.core.RowMapper;
48
49/**
50 * Created on : Jun 27, 2013, 10:30:52 AM
51 *
52 * @author Peter Withers <peter.withers@mpi.nl>
53 */
54public class JdbcAnnotationDao extends JdbcResourceDao implements AnnotationDao {
55
56    @Autowired
57    PermissionsDao jdbcPermissionsDao;
58    @Autowired
59    UserDao jdbcUserDao;
60    @Autowired
61    NotebookDao jdbcNotebookDao;
62    @Autowired
63    SourceDao jdbcSourceDao;
64
65    public JdbcAnnotationDao(DataSource dataSource) {
66        setDataSource(dataSource);
67        internalIdName = annotation_id;
68        resourceTableName = annotationTableName;
69    }
70
71    @Override
72    public List<Number> getFilteredAnnotationIDs(String link, String text, String access, String namespace, UserIdentifier owner, Timestamp after, Timestamp before) {
73
74        String sql = "SELECT " + annotation_id + " FROM " + annotationTableName;
75        boolean firstClauseIsBuild = false;
76        //TODO: optimize List<Object> params = new ArrayList<Object>();
77        //TODO: optimizie String builder
78
79
80
81        if (owner != null) {
82            sql = sql + " WHERE " + principal_id + "=:owner" + jdbcUserDao.getInternalID(owner);
83            firstClauseIsBuild = true;
84        }
85
86
87
88        if (after != null) {
89            if (firstClauseIsBuild) {
90                sql = sql + " AND " + time_stamp + "  > " + after.toString();
91            } else {
92                sql = sql + " WHERE " + time_stamp + "  > " + after.toString();
93                firstClauseIsBuild = true;
94            }
95        }
96
97        if (before != null) {
98            if (firstClauseIsBuild) {
99                sql = sql + " AND " + time_stamp + "  < " + before.toString();
100            } else {
101                sql = sql + " WHERE " + time_stamp + "  < " + before.toString();
102                firstClauseIsBuild = true;
103            }
104        }
105
106        if (text != null) {
107            if (firstClauseIsBuild) {
108                sql = sql + " AND " + body_xml + "  LIKE '%" + text + "%'";
109            } else {
110                sql = sql + " WHERE " + body_xml + "  LIKE '%" + text + "%'";
111                firstClauseIsBuild = true;
112            }
113        }
114
115        if (link != null) {
116            List<Number> sourceIDs = jdbcSourceDao.getSourcesForLink(link);
117            if (!sourceIDs.isEmpty()) {
118                String values = makeListOfValues(sourceIDs);
119                if (firstClauseIsBuild) {
120                    sql = sql + " AND " + source_id + " IN " + values;
121                }
122                 else {
123                    sql = sql + " WHERE " + source_id + " IN " + values;
124                    firstClauseIsBuild = true;
125                }
126            }
127        }
128
129
130        List<Number> result = getSimpleJdbcTemplate().query(sql, internalIDRowMapper);
131        return result;
132    }
133
134    @Override
135    public List<AnnotationInfo> getAnnotationInfos(List<Number> annotationIDs) {
136
137        if (annotationIDs == null) {
138            return null;
139        }
140
141        if (annotationIDs.isEmpty()) {
142            return (new ArrayList<AnnotationInfo>());
143        }
144
145        String values = makeListOfValues(annotationIDs);
146        String sql = "SELECT " + annotationStar + " FROM " + annotationTableName + " WHERE " + annotationAnnotation_id + "  IN " + values;
147        return getSimpleJdbcTemplate().query(sql, annotationInfoRowMapper);
148    }
149    private final RowMapper<AnnotationInfo> annotationInfoRowMapper = new RowMapper<AnnotationInfo>() {
150        @Override
151        public AnnotationInfo mapRow(ResultSet rs, int rowNumber) throws SQLException {
152            AnnotationInfo annotationInfo = new AnnotationInfo();
153            annotationInfo.setOwner(getResourceREF(Integer.toString(rs.getInt(owner_id))));
154            annotationInfo.setHeadline(rs.getString(headline));
155            return annotationInfo;
156        }
157    };
158
159    /////////////////////////////////////////////////
160    /**
161     *
162     * @param annotationIDs
163     * @return list of annotation references corresponding to the annotation-ids
164     * from the input list if the input list is null or empty (zero elements)
165     * returns an empty list
166     */
167    @Override
168    public List<ResourceREF> getAnnotationREFs(List<Number> annotationIDs) {
169
170        if (annotationIDs == null) {
171            return null;
172        }
173
174        if (annotationIDs.isEmpty()) {
175            return (new ArrayList<ResourceREF>());
176        }
177
178        String values = makeListOfValues(annotationIDs);
179        String sql = "SELECT " + annotationAnnotation_id + " FROM " + annotationTableName + " WHERE " + annotationAnnotation_id + "  IN " + values;
180        return getSimpleJdbcTemplate().query(sql, annotationREFRowMapper);
181    }
182    private final RowMapper<ResourceREF> annotationREFRowMapper = new RowMapper<ResourceREF>() {
183        @Override
184        public ResourceREF mapRow(ResultSet rs, int rowNumber) throws SQLException {
185            ResourceREF annotationREF = new ResourceREF();
186            annotationREF.setRef(Integer.toString(rs.getInt(annotation_id)));
187            return annotationREF;
188        }
189    };
190
191    //////////////////////////////////////////////////////////////////////////
192    @Override
193    public Annotation getAnnotation(Number annotationID) throws SQLException {
194        if (annotationID == null) {
195            return null;
196        }
197        String sql = "SELECT " + annotationStar + " FROM " + annotationTableName + " WHERE " + annotationAnnotation_id + "= ?";
198        List<Annotation> result = getSimpleJdbcTemplate().query(sql, annotationRowMapper, annotationID);
199
200        if (result == null) {
201            return null;
202        }
203        if (result.isEmpty()) {
204            return null;
205        }
206        return result.get(0);
207    }
208    private final RowMapper<Annotation> annotationRowMapper = new RowMapper<Annotation>() {
209        @Override
210        public Annotation mapRow(ResultSet rs, int rowNumber) throws SQLException {
211            Annotation result = new Annotation();
212
213            ResourceREF ownerREF = new ResourceREF();
214            ownerREF.setRef(String.valueOf(rs.getInt(owner_id)));
215            result.setOwner(ownerREF);
216
217            result.setHeadline(rs.getString(headline));
218
219            result.setBody(convertToAnnotationBody(rs.getString(body_xml)));
220
221            List<SourceInfo> sourceInfoList = jdbcSourceDao.getSourceInfos(rs.getInt(annotation_id));
222            NewOrExistingSourceInfos noeSourceInfos = jdbcSourceDao.contructNewOrExistingSourceInfo(sourceInfoList);
223            result.setTargetSources(noeSourceInfos);
224
225            // TODO: fix: rpelace URI in the schema with external id, or make here the conversion:
226            // from external ID in the DB to the URI for the class
227            result.setURI(rs.getString(external_id));
228
229            try {
230                result.setTimeStamp(Helpers.setXMLGregorianCalendar(rs.getTimestamp(time_stamp)));
231                return result;
232            } catch (DatatypeConfigurationException e) {
233                System.out.println(e);
234                return result; // no date-time is set
235            }
236        }
237    };
238
239    private AnnotationBody convertToAnnotationBody(String input) {
240        if (input == null) {
241            return null;
242        }
243
244        AnnotationBody result = new AnnotationBody();
245        List<Object> element = result.getAny();
246        element.add(input);
247        return result;
248    }
249
250    @Override
251    public int deleteAnnotation(Number annotationId) throws SQLException {
252
253        String sqlNotebooks = "DELETE FROM " + notebooksAnnotationsTableName + " where " + annotation_id + " = ?";
254        int affectedNotebooks = getSimpleJdbcTemplate().update(sqlNotebooks, annotationId);
255
256        String sqlPermissions = "DELETE FROM " + permissionsTableName + " where " + annotation_id + " = ?";
257        int affectedPermissions = getSimpleJdbcTemplate().update(sqlPermissions, annotationId);
258
259        // safe removing sources
260        List<Number> sourceIDs = jdbcSourceDao.retrieveSourceIDs(annotationId);
261        String sqlTargetSources = "DELETE FROM " + annotationsSourcesTableName + " where " + annotation_id + " = ?";
262        int affectedAnnotationsSources = getSimpleJdbcTemplate().update(sqlTargetSources, annotationId);
263        int affectedSources;
264        for (Number sourceID : sourceIDs) {
265            // call  the method in sources DAO that handles removal of a source which is not refered by other annotations
266            affectedSources = jdbcSourceDao.deleteSource(sourceID);
267        }
268
269        String sqlAnnotation = "DELETE FROM " + annotationTableName + " where " + annotation_id + " = ?";
270        int affectedAnnotations = getSimpleJdbcTemplate().update(sqlAnnotation, annotationId);
271        if (affectedAnnotations > 1) {
272            throw new SQLException("There was more than one annotation (" + affectedAnnotations + ") with the same ID " + annotationId);
273        }
274        return affectedAnnotations;
275        //TODO implement deleting sources (see the specification document and the interfaces' javadoc
276    }
277
278    // TODO: so far URI in the xml is the same as the external_id in the DB!!
279    // Change it when the decision is taken!!!
280    @Override
281    public Annotation addAnnotation(Annotation annotation, Number ownerID) throws SQLException {
282
283        Annotation result = makeDeepCopy(annotation);
284
285        ResourceREF ownerRef = new ResourceREF();
286        ownerRef.setRef(String.valueOf(ownerID));
287        result.setOwner(ownerRef);
288
289        // generate a new annotation ID
290        AnnotationIdentifier annotationIdentifier = new AnnotationIdentifier();
291        result.setURI(annotationIdentifier.toString());
292
293        Map<String, Object> params = new HashMap<String, Object>();
294        params.put("externalId", annotationIdentifier.toString());
295        //params.put("timeStamp", annotation.getTimeStamp()); is generated while adding the annotation in the DB as "now"
296        params.put("ownerId", ownerID);
297        params.put("headline", annotation.getHeadline());
298        params.put("bodyXml", annotation.getBody().getAny().get(0).toString());
299
300        try {
301
302            String sql = "INSERT INTO " + annotationTableName + "(" + external_id + "," + owner_id + "," + headline + "," + body_xml + " ) VALUES (:externalId, :ownerId, :headline, :bodyXml)";
303            final int affectedRows = getSimpleJdbcTemplate().update(sql, params);
304
305            if (affectedRows != 1) {
306                throw (new SQLException("Cannot add the annotation properly"));
307            }
308
309            Number internalID = getInternalID(annotationIdentifier);
310
311            //retrieve taime stamp for the just added annotation
312            result.setTimeStamp(retrieveTimeStamp(internalID));
313
314            // place new target sources in the DB, when necessary, update the corresponding target source info for the result
315            // the joint annotations_target_sources" tabel is updated.
316            List<NewOrExistingSourceInfo> sources = result.getTargetSources().getTarget();
317            Map<NewOrExistingSourceInfo, NewOrExistingSourceInfo> sourcePairs = jdbcSourceDao.addTargetSources(internalID, sources);
318            sources.clear();
319            sources.addAll(sourcePairs.values());
320
321            //replace the temporary sourceId-references in the body with the persistent externalId
322            String body = annotation.getBody().getAny().get(0).toString();
323            String newBody = updateTargetRefsInBody(body, sourcePairs);
324            List<Object> bodyXML = result.getBody().getAny();
325            bodyXML.clear();
326            bodyXML.add(newBody);
327            String sqlUpdate = "UPDATE " + annotationTableName + " SET " + body_xml + "= ? WHERE " + annotation_id + "= " + internalID;
328            int affectedRowsBodyUpd = getSimpleJdbcTemplate().update(sqlUpdate, newBody);
329            if (affectedRows != 1) {
330                throw (new SQLException("Cannot update the body with persistent reference ID"));
331            }
332
333            return result;
334        } catch (DataAccessException exception) {
335            throw exception;
336        }
337    }
338
339    //////////////////////////////////////////////////
340    @Override
341    public AnnotationIdentifier getExternalID(Number internalID) {
342        return new AnnotationIdentifier(super.getExternalIdentifier(internalID));
343    }
344
345    //////////// helpers ///////////////////////
346    /////////////////////////////////////////////////
347    private String updateTargetRefsInBody(String body, Map<NewOrExistingSourceInfo, NewOrExistingSourceInfo> sourcePairs) {
348        String result = body;
349        for (NewOrExistingSourceInfo tempSource : sourcePairs.keySet()) {
350            NewSourceInfo newSource = tempSource.getNewSource();
351            if (newSource != null) {
352                result = result.replaceAll(newSource.getId(), sourcePairs.get(tempSource).getSource().getRef());
353            }
354        }
355        return result;
356    }
357
358    ///////////////////////////////////////////////////////////
359    private ResourceREF getResourceREF(String resourceID) {
360        ResourceREF result = new ResourceREF();
361        result.setRef(resourceID);
362        return result;
363    }
364
365    ////////////////////////////////////////// 
366    private Annotation makeDeepCopy(Annotation annotation) {
367
368        if (annotation == null) {
369            return null;
370        }
371
372        Annotation result = new Annotation();
373
374        AnnotationBody body = new AnnotationBody();
375        String bodyString = annotation.getBody().getAny().get(0).toString();
376        body.getAny().add(bodyString);
377        result.setBody(body);
378
379        result.setHeadline(annotation.getHeadline());
380
381        ResourceREF owner = new ResourceREF();
382        owner.setRef(annotation.getOwner().getRef());
383        result.setOwner(owner);
384
385//        ResourceREF permissions = new ResourceREF();
386//        permissions.setRef(annotation.getPermissions().getRef());
387//        result.setPermissions(permissions);
388
389        result.setPermissions(null); //we do not have permissions there
390
391        NewOrExistingSourceInfos noesi = new NewOrExistingSourceInfos();
392        noesi.getTarget().addAll(annotation.getTargetSources().getTarget());
393        result.setTargetSources(noesi);
394
395        result.setTimeStamp(annotation.getTimeStamp());
396        result.setURI(annotation.getURI());
397
398        return result;
399    }
400}
Note: See TracBrowser for help on using the repository browser.