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.webdav;
025:
026: import java.io.IOException;
027: import java.util.List;
028: import java.util.UUID;
029: import jeeves.interfaces.Logger;
030: import jeeves.resources.dbms.Dbms;
031: import jeeves.server.context.ServiceContext;
032: import jeeves.utils.Xml;
033: import org.fao.geonet.GeonetContext;
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.Privileges;
039: import org.fao.geonet.kernel.harvest.harvester.UriMapper;
040: import org.jdom.Element;
041: import org.jdom.JDOMException;
042:
043: //=============================================================================
044:
045: class Harvester {
046: //--------------------------------------------------------------------------
047: //---
048: //--- Constructor
049: //---
050: //--------------------------------------------------------------------------
051:
052: public Harvester(Logger log, ServiceContext context, Dbms dbms,
053: WebDavParams params) {
054: this .log = log;
055: this .context = context;
056: this .dbms = dbms;
057: this .params = params;
058:
059: result = new WebDavResult();
060:
061: GeonetContext gc = (GeonetContext) context
062: .getHandlerContext(Geonet.CONTEXT_NAME);
063: dataMan = gc.getDataManager();
064: }
065:
066: //---------------------------------------------------------------------------
067: //---
068: //--- API methods
069: //---
070: //---------------------------------------------------------------------------
071:
072: public WebDavResult harvest() throws Exception {
073: log.info("Retrieving remote metadata information for : "
074: + params.name);
075:
076: RemoteRetriever rr = new WebDavRetriever();
077: rr.init(log, context, params);
078: List<RemoteFile> files = rr.retrieve();
079:
080: log.info("Remote files found : " + files.size());
081:
082: align(files);
083: rr.destroy();
084:
085: return result;
086: }
087:
088: //---------------------------------------------------------------------------
089: //---
090: //--- Private methods
091: //---
092: //---------------------------------------------------------------------------
093:
094: private void align(List<RemoteFile> files) throws Exception {
095: log.info("Start of alignment for : " + params.name);
096:
097: //-----------------------------------------------------------------------
098: //--- retrieve all local categories and groups
099: //--- retrieve harvested uuids for given harvesting node
100:
101: localCateg = new CategoryMapper(dbms);
102: localGroups = new GroupMapper(dbms);
103: localUris = new UriMapper(dbms, params.uuid);
104: dbms.commit();
105:
106: //-----------------------------------------------------------------------
107: //--- remove old metadata
108:
109: for (String uri : localUris.getUris())
110: if (!exists(files, uri)) {
111: String id = localUris.getID(uri);
112:
113: log.debug(" - Removing old metadata with local id:"
114: + id);
115: dataMan.deleteMetadata(dbms, id);
116: dbms.commit();
117: result.locallyRemoved++;
118: }
119:
120: //-----------------------------------------------------------------------
121: //--- insert/update new metadata
122:
123: for (RemoteFile rf : files) {
124: result.total++;
125:
126: String id = localUris.getID(rf.getPath());
127:
128: if (id == null)
129: addMetadata(rf);
130: else
131: updateMetadata(rf, id);
132: }
133:
134: log.info("End of alignment for : " + params.name);
135: }
136:
137: //--------------------------------------------------------------------------
138: /** Return true if the uri is present in the remote folder */
139:
140: private boolean exists(List<RemoteFile> files, String uri) {
141: for (RemoteFile rf : files)
142: if (uri.equals(rf.getPath()))
143: return true;
144:
145: return false;
146: }
147:
148: //--------------------------------------------------------------------------
149: //---
150: //--- Private methods : addMetadata
151: //---
152: //--------------------------------------------------------------------------
153:
154: private void addMetadata(RemoteFile rf) throws Exception {
155: Element md = retrieveMetadata(rf);
156:
157: if (md == null)
158: return;
159:
160: //--- schema handled check already done
161:
162: String schema = dataMan.autodetectSchema(md);
163: String uuid = UUID.randomUUID().toString();
164:
165: log.debug(" - Setting uuid for metadata with remote path : "
166: + rf.getPath());
167:
168: //--- set uuid inside metadata and get new xml
169: md = dataMan.setUUID(schema, uuid, md);
170:
171: log.debug(" - Adding metadata with remote path : "
172: + rf.getPath());
173:
174: String id = dataMan.insertMetadataExt(dbms, schema, md, context
175: .getSerialFactory(), params.uuid, rf.getChangeDate(),
176: rf.getChangeDate(), uuid, 1, null);
177:
178: int iId = Integer.parseInt(id);
179:
180: dataMan.setTemplate(dbms, iId, "n", null);
181: dataMan.setHarvested(dbms, iId, params.uuid, rf.getPath());
182:
183: addPrivileges(id);
184: addCategories(id);
185:
186: dbms.commit();
187: dataMan.indexMetadata(dbms, id);
188: result.added++;
189: }
190:
191: //--------------------------------------------------------------------------
192:
193: private Element retrieveMetadata(RemoteFile rf) {
194: try {
195: log.debug("Getting remote file : " + rf.getPath());
196: Element md = rf.getMetadata();
197: log.debug("Record got:\n" + Xml.getString(md));
198:
199: String schema = dataMan.autodetectSchema(md);
200:
201: if (schema == null) {
202: log
203: .warning("Skipping metadata with unknown schema. Path is : "
204: + rf.getPath());
205: result.unknownSchema++;
206: } else {
207: if (!params.validate || validates(schema, md))
208: return (Element) md.detach();
209:
210: log
211: .warning("Skipping metadata that does not validate. Path is : "
212: + rf.getPath());
213: result.doesNotValidate++;
214: }
215: }
216:
217: catch (JDOMException e) {
218: log
219: .warning("Skipping metadata with bad XML format. Path is : "
220: + rf.getPath());
221: result.badFormat++;
222: }
223:
224: catch (Exception e) {
225: log
226: .warning("Raised exception while getting metadata file : "
227: + e);
228: result.unretrievable++;
229: }
230:
231: //--- we don't raise any exception here. Just try to go on
232: return null;
233: }
234:
235: //--------------------------------------------------------------------------
236:
237: private boolean validates(String schema, Element md) {
238: try {
239: dataMan.validate(schema, md);
240: return true;
241: } catch (Exception e) {
242: return false;
243: }
244: }
245:
246: //--------------------------------------------------------------------------
247: //--- Categories
248: //--------------------------------------------------------------------------
249:
250: private void addCategories(String id) throws Exception {
251: for (String catId : params.getCategories()) {
252: String name = localCateg.getName(catId);
253:
254: if (name == null)
255: log.debug(" - Skipping removed category with id:"
256: + catId);
257: else {
258: log.debug(" - Setting category : " + name);
259: dataMan.setCategory(dbms, id, catId);
260: }
261: }
262: }
263:
264: //--------------------------------------------------------------------------
265: //--- Privileges
266: //--------------------------------------------------------------------------
267:
268: private void addPrivileges(String id) throws Exception {
269: for (Privileges priv : params.getPrivileges()) {
270: String name = localGroups.getName(priv.getGroupId());
271:
272: if (name == null)
273: log.debug(" - Skipping removed group with id:"
274: + priv.getGroupId());
275: else {
276: log.debug(" - Setting privileges for group : "
277: + name);
278:
279: for (int opId : priv.getOperations()) {
280: name = dataMan.getAccessManager().getPrivilegeName(
281: opId);
282:
283: //--- allow only: view, dynamic, featured
284: if (opId == 0 || opId == 5 || opId == 6) {
285: log.debug(" --> " + name);
286: dataMan.setOperation(dbms, id, priv
287: .getGroupId(), opId + "");
288: } else
289: log.debug(" --> " + name + " (skipped)");
290: }
291: }
292: }
293: }
294:
295: //--------------------------------------------------------------------------
296: //---
297: //--- Private methods : updateMetadata
298: //---
299: //--------------------------------------------------------------------------
300:
301: private void updateMetadata(RemoteFile rf, String id)
302: throws Exception {
303: String date = localUris.getChangeDate(rf.getPath());
304:
305: if (!rf.isMoreRecentThan(date)) {
306: log.debug(" - Metadata XML not changed for path : "
307: + rf.getPath());
308: result.unchanged++;
309: } else {
310: log.debug(" - Updating local metadata for path : "
311: + rf.getPath());
312:
313: Element md = retrieveMetadata(rf);
314:
315: if (md == null)
316: return;
317:
318: dataMan.updateMetadataExt(dbms, id, md, rf.getChangeDate());
319:
320: //--- the administrator could change privileges and categories using the
321: //--- web interface so we have to re-set both
322:
323: dbms.execute(
324: "DELETE FROM OperationAllowed WHERE metadataId=?",
325: Integer.parseInt(id));
326: addPrivileges(id);
327:
328: dbms.execute(
329: "DELETE FROM MetadataCateg WHERE metadataId=?",
330: Integer.parseInt(id));
331: addCategories(id);
332:
333: dbms.commit();
334: dataMan.indexMetadata(dbms, id);
335: result.updated++;
336: }
337: }
338:
339: //---------------------------------------------------------------------------
340: //---
341: //--- Variables
342: //---
343: //---------------------------------------------------------------------------
344:
345: private Logger log;
346: private ServiceContext context;
347: private Dbms dbms;
348: private WebDavParams params;
349: private DataManager dataMan;
350: private CategoryMapper localCateg;
351: private GroupMapper localGroups;
352: private UriMapper localUris;
353: private WebDavResult result;
354: }
355:
356: //=============================================================================
357:
358: interface RemoteRetriever {
359: public void init(Logger log, ServiceContext context,
360: WebDavParams params);
361:
362: public List<RemoteFile> retrieve() throws Exception;
363:
364: public void destroy();
365: }
366:
367: //=============================================================================
368:
369: interface RemoteFile {
370: public String getPath();
371:
372: public String getChangeDate();
373:
374: public Element getMetadata() throws JDOMException, IOException,
375: Exception;
376:
377: public boolean isMoreRecentThan(String localDate);
378: }
379:
380: //=============================================================================
|