001: //=============================================================================
002: //=== Copyright (C) 2001-2007 Food and Agriculture Organization of the
003: //=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
004: //=== and United Nations Environment Programme (UNEP)
005: //===
006: //=== This program is free software; you can redistribute it and/or modify
007: //=== it under the terms of the GNU General Public License as published by
008: //=== the Free Software Foundation; either version 2 of the License, or (at
009: //=== your option) any later version.
010: //===
011: //=== This program is distributed in the hope that it will be useful, but
012: //=== WITHOUT ANY WARRANTY; without even the implied warranty of
013: //=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: //=== General Public License for more details.
015: //===
016: //=== You should have received a copy of the GNU General Public License
017: //=== along with this program; if not, write to the Free Software
018: //=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
019: //===
020: //=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
021: //=== Rome - Italy. email: geonetwork@osgeo.org
022: //==============================================================================
023:
024: package org.fao.geonet.kernel.harvest.harvester.geonet20;
025:
026: import java.util.Iterator;
027: import java.util.List;
028: import jeeves.interfaces.Logger;
029: import jeeves.resources.dbms.Dbms;
030: import jeeves.server.context.ServiceContext;
031: import jeeves.utils.Util;
032: import jeeves.utils.XmlRequest;
033: import org.fao.geonet.constants.Edit;
034: import org.fao.geonet.constants.Geonet;
035: import org.fao.geonet.kernel.DataManager;
036: import org.fao.geonet.kernel.harvest.harvester.CategoryMapper;
037: import org.fao.geonet.kernel.harvest.harvester.GroupMapper;
038: import org.fao.geonet.kernel.harvest.harvester.UUIDMapper;
039: import org.fao.geonet.util.ISODate;
040: import org.jdom.Element;
041:
042: //=============================================================================
043:
044: public class Aligner {
045: //--------------------------------------------------------------------------
046: //---
047: //--- Constructor
048: //---
049: //--------------------------------------------------------------------------
050:
051: public Aligner(Logger log, XmlRequest req, GeonetParams params,
052: DataManager dm, Dbms dbms, ServiceContext sc,
053: CategoryMapper cm, GroupMapper gm) {
054: this .log = log;
055: this .req = req;
056: this .params = params;
057: this .dataMan = dm;
058: this .dbms = dbms;
059: this .context = sc;
060: this .localCateg = cm;
061: this .localGroups = gm;
062: }
063:
064: //--------------------------------------------------------------------------
065: //---
066: //--- Alignment method
067: //---
068: //--------------------------------------------------------------------------
069:
070: public AlignerResult align(Element result, String siteId)
071: throws Exception {
072: log.info("Start of alignment for site-id=" + siteId);
073:
074: this .result = new AlignerResult();
075: this .result.siteId = siteId;
076:
077: List mdList = result.getChildren("metadata");
078:
079: //-----------------------------------------------------------------------
080: //--- retrieve local uuids for given site-id
081:
082: localUuids = new UUIDMapper(dbms, siteId);
083:
084: //-----------------------------------------------------------------------
085: //--- remove old metadata
086:
087: for (String uuid : localUuids.getUUIDs())
088: if (!exists(mdList, uuid)) {
089: String id = localUuids.getID(uuid);
090:
091: log.debug(" - Removing old metadata with id=" + id);
092: dataMan.deleteMetadata(dbms, id);
093: dbms.commit();
094: this .result.locallyRemoved++;
095: }
096:
097: //-----------------------------------------------------------------------
098: //--- insert/update new metadata
099:
100: for (Iterator i = mdList.iterator(); i.hasNext();) {
101: Element info = ((Element) i.next()).getChild("info",
102: Edit.NAMESPACE);
103:
104: String remoteId = info.getChildText("id");
105: String remoteUuid = info.getChildText("uuid");
106: String schema = info.getChildText("schema");
107: String changeDate = info.getChildText("changeDate");
108:
109: this .result.totalMetadata++;
110:
111: log.debug("Obtained remote id=" + remoteId
112: + ", changeDate=" + changeDate);
113:
114: if (!dataMan.existsSchema(schema)) {
115: log
116: .debug(" - Skipping unsupported schema : "
117: + schema);
118: this .result.schemaSkipped++;
119: } else {
120: String id = dataMan.getMetadataId(dbms, remoteUuid);
121:
122: if (id == null)
123: id = addMetadata(siteId, info);
124: else
125: updateMetadata(siteId, info, id);
126:
127: dbms.commit();
128:
129: //--- maybe the metadata was unretrievable
130:
131: if (id != null)
132: dataMan.indexMetadata(dbms, id);
133: }
134: }
135:
136: log.info("End of alignment for site-id=" + siteId);
137:
138: return this .result;
139: }
140:
141: //--------------------------------------------------------------------------
142: //---
143: //--- Private methods : addMetadata
144: //---
145: //--------------------------------------------------------------------------
146:
147: private String addMetadata(String siteId, Element info)
148: throws Exception {
149: String remoteId = info.getChildText("id");
150: String remoteUuid = info.getChildText("uuid");
151: String schema = info.getChildText("schema");
152: String createDate = info.getChildText("createDate");
153: String changeDate = info.getChildText("changeDate");
154:
155: log.debug(" - Adding metadata with remote id=" + remoteId);
156:
157: Element md = getRemoteMetadata(req, remoteId);
158:
159: if (md == null) {
160: log
161: .warning(" - Cannot get metadata (possibly bad XML) with remote id="
162: + remoteId);
163: return null;
164: }
165:
166: String id = dataMan.insertMetadataExt(dbms, schema, md, context
167: .getSerialFactory(), params.uuid, createDate,
168: changeDate, remoteUuid, 1, null);
169:
170: int iId = Integer.parseInt(id);
171:
172: dataMan.setTemplate(dbms, iId, "n", null);
173: dataMan.setHarvested(dbms, iId, params.uuid);
174:
175: result.addedMetadata++;
176:
177: addCategories(id, info.getChildren("category"));
178: addPrivileges(id, info);
179:
180: return id;
181: }
182:
183: //--------------------------------------------------------------------------
184: //--- Categories
185: //--------------------------------------------------------------------------
186:
187: private void addCategories(String id, List categ) throws Exception {
188: for (Iterator j = categ.iterator(); j.hasNext();) {
189: String catName = ((Element) j.next()).getText();
190: String catId = localCateg.getID(catName);
191:
192: if (catId != null) {
193: //--- remote category exists locally
194:
195: log.debug(" - Setting category : " + catName);
196: dataMan.setCategory(dbms, id, catId);
197: }
198: }
199: }
200:
201: //--------------------------------------------------------------------------
202: //--- Privileges
203: //--------------------------------------------------------------------------
204:
205: private void addPrivileges(String id, Element info)
206: throws Exception {
207: //--- set view privilege for both groups 'intranet' and 'all'
208: dataMan.setOperation(dbms, id, "0", "0");
209: dataMan.setOperation(dbms, id, "1", "0");
210: }
211:
212: //--------------------------------------------------------------------------
213: //---
214: //--- Private methods : updateMetadata
215: //---
216: //--------------------------------------------------------------------------
217:
218: private void updateMetadata(String siteId, Element info, String id)
219: throws Exception {
220: String remoteId = info.getChildText("id");
221: String remoteUuid = info.getChildText("uuid");
222: String changeDate = info.getChildText("changeDate");
223:
224: if (localUuids.getID(remoteUuid) == null) {
225: log.error(" - Warning! The remote uuid '" + remoteUuid
226: + "' does not belong to site '" + siteId + "'");
227: log
228: .error(" - The site id of this metadata has been changed.");
229: log.error(" - The metadata update will be skipped.");
230:
231: result.uuidSkipped++;
232: } else {
233: updateMetadata(id, remoteId, remoteUuid, changeDate);
234: updateCategories(id, info);
235: }
236: }
237:
238: //--------------------------------------------------------------------------
239:
240: private void updateMetadata(String id, String remoteId,
241: String remoteUuid, String changeDate) throws Exception {
242: String date = localUuids.getChangeDate(remoteUuid);
243:
244: if (!updateCondition(date, changeDate)) {
245: log.debug(" - XML not changed to local metadata with id="
246: + id);
247: result.unchangedMetadata++;
248: } else {
249: log.debug(" - Updating local metadata with id=" + id);
250:
251: Element md = getRemoteMetadata(req, remoteId);
252:
253: if (md == null)
254: log
255: .warning(" - Cannot get metadata (possibly bad XML) with remote id="
256: + remoteId);
257: else {
258: dataMan.updateMetadataExt(dbms, id, md, changeDate);
259: result.updatedMetadata++;
260: }
261: }
262: }
263:
264: //--------------------------------------------------------------------------
265:
266: private void updateCategories(String id, Element info)
267: throws Exception {
268: List catList = info.getChildren("category");
269:
270: //--- remove old categories
271:
272: List locCateg = dataMan.getCategories(dbms, id).getChildren();
273:
274: for (int i = 0; i < locCateg.size(); i++) {
275: Element el = (Element) locCateg.get(i);
276:
277: String catId = el.getChildText("id");
278: String catName = el.getChildText("name");
279:
280: if (!existsCategory(catList, catName)) {
281: log.debug(" - Unsetting category : " + catName);
282: dataMan.unsetCategory(dbms, id, catId);
283: }
284: }
285:
286: //--- add new categories
287:
288: for (Iterator j = catList.iterator(); j.hasNext();) {
289: Element categ = (Element) j.next();
290: String catName = categ.getAttributeValue("name");
291: String catId = localCateg.getID(catName);
292:
293: if (catId != null)
294: //--- it is not necessary to query the db. Anyway...
295: if (!dataMan.isCategorySet(dbms, id, catId)) {
296: log.debug(" - Setting category : " + catName);
297: dataMan.setCategory(dbms, id, catId);
298: }
299: }
300: }
301:
302: //--------------------------------------------------------------------------
303:
304: private boolean existsCategory(List catList, String name) {
305: for (Iterator i = catList.iterator(); i.hasNext();) {
306: Element categ = (Element) i.next();
307: String catName = categ.getText();
308:
309: if (catName.equals(name))
310: return true;
311: }
312:
313: return false;
314: }
315:
316: //--------------------------------------------------------------------------
317: //---
318: //--- Private methods
319: //---
320: //--------------------------------------------------------------------------
321:
322: private Element getRemoteMetadata(XmlRequest req, String id)
323: throws Exception {
324: req.setAddress("/" + params.servlet + "/srv/en/"
325: + Geonet.Service.XML_METADATA_GET);
326: req.clearParams();
327: req.addParam("id", id);
328:
329: try {
330: Element md = req.execute();
331: Element info = md.getChild("info", Edit.NAMESPACE);
332:
333: if (info != null)
334: info.detach();
335:
336: return md;
337: } catch (Exception e) {
338: log
339: .warning("Cannot retrieve remote metadata with id:"
340: + id);
341: log.warning(" (C) Error is : " + e.getMessage());
342:
343: return null;
344: }
345: }
346:
347: //--------------------------------------------------------------------------
348: /** Return true if the sourceId is present in the remote site */
349:
350: private boolean exists(List mdList, String uuid) {
351: for (Iterator i = mdList.iterator(); i.hasNext();) {
352: Element elInfo = ((Element) i.next()).getChild("info",
353: Edit.NAMESPACE);
354:
355: if (uuid.equals(elInfo.getChildText("uuid")))
356: return true;
357: }
358:
359: return false;
360: }
361:
362: //--------------------------------------------------------------------------
363:
364: private boolean updateCondition(String localDate, String remoteDate) {
365: ISODate local = new ISODate(localDate);
366: ISODate remote = new ISODate(remoteDate);
367:
368: //--- accept if remote date is greater than local date
369:
370: return (remote.sub(local) > 0);
371: }
372:
373: //--------------------------------------------------------------------------
374: //---
375: //--- Variables
376: //---
377: //--------------------------------------------------------------------------
378:
379: private Dbms dbms;
380: private Logger log;
381: private XmlRequest req;
382: private GeonetParams params;
383: private DataManager dataMan;
384: private ServiceContext context;
385: private CategoryMapper localCateg;
386: private GroupMapper localGroups;
387: private UUIDMapper localUuids;
388: private AlignerResult result;
389: }
390:
391: //=============================================================================
392:
393: class AlignerResult {
394: public String siteId;
395:
396: public int totalMetadata;
397: public int addedMetadata;
398: public int updatedMetadata;
399: public int unchangedMetadata;
400: public int locallyRemoved;
401: public int schemaSkipped;
402: public int uuidSkipped;
403: }
404:
405: //=============================================================================
|