Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A class that gets Accession Number, check for uniqueness
4
 *             and register it into db
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Jivka Bojilova, Matt Jones
8
 *
9
 *   '$Author: leinfelder $'
10
 *     '$Date: 2011-11-02 20:40:12 -0700 (Wed, 02 Nov 2011) $'
11
 * '$Revision: 6595 $'
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 */
27
package edu.ucsb.nceas.metacat.index;
28

    
29
import java.io.FileInputStream;
30
import java.io.FileNotFoundException;
31
import java.io.InputStream;
32
import java.util.ArrayList;
33
import java.util.Date;
34
import java.util.List;
35
import java.util.TimerTask;
36

    
37
import org.apache.commons.logging.Log;
38
import org.apache.commons.logging.LogFactory;
39
import org.apache.solr.client.solrj.SolrServerException;
40
import org.dataone.configuration.Settings;
41
import org.dataone.service.exceptions.InvalidRequest;
42
import org.dataone.service.exceptions.InvalidToken;
43
import org.dataone.service.exceptions.NotAuthorized;
44
import org.dataone.service.exceptions.NotImplemented;
45
import org.dataone.service.exceptions.ServiceFailure;
46
import org.dataone.service.types.v1.Identifier;
47
import org.dataone.service.types.v1.ObjectFormatIdentifier;
48
import org.dataone.service.types.v1.SystemMetadata;
49

    
50
import com.hazelcast.core.IMap;
51
import com.hazelcast.core.ISet;
52

    
53
import edu.ucsb.nceas.metacat.index.event.EventlogFactory;
54
import edu.ucsb.nceas.metacat.index.event.IndexEvent;
55
import edu.ucsb.nceas.metacat.index.event.IndexEventLogException;
56

    
57

    
58
/**
59
 * A class represents the object to generate massive solr indexes.
60
 * This can happen during an update of Metacat (generating index for all existing documents)
61
 * or regenerate index for those documents
62
 * failing to build index during the insert or update.
63
 * 
64
 * @author tao
65
 *
66
 */
67
public class IndexGenerator extends TimerTask {
68
    
69
    private static final int FIRST =0;
70
    private static final int SECOND =1;
71
    public static final int WAITTIME = 10000;
72
    public static final int MAXWAITNUMBER = 180;
73
    private static final String HTTP = "http://";
74
    private static final String MNAPPENDIX = "/d1/mn";
75
    private static final String RESOURCEMAPPROPERYNAME = "index.resourcemap.namespace";
76
    public static final String WAITIMEPOPERTYNAME = "index.regenerate.start.waitingtime";
77
    public static final String MAXATTEMPTSPROPERTYNAME = "index.regenerate.start.maxattempts";
78
    
79
    private static int waitingTime = WAITTIME;
80
    private static int maxAttempts = MAXWAITNUMBER;
81
    
82
    private SolrIndex solrIndex = null;
83
    //private SystemMetadataEventListener systemMetadataListener = null;
84
    private IMap<Identifier, SystemMetadata> systemMetadataMap;
85
    private IMap<Identifier, String> objectPathMap;
86
    private Log log = LogFactory.getLog(IndexGenerator.class);
87
    //private MNode mNode = null;
88
    private static List<String> resourceMapNamespaces = null;
89
    
90
    /**
91
     * Constructor
92
     * @param solrIndex
93
     * @param systemMetadataListener
94
     */
95
    public IndexGenerator(SolrIndex solrIndex) {
96
        this.solrIndex = solrIndex;
97
        resourceMapNamespaces = Settings.getConfiguration().getList(RESOURCEMAPPROPERYNAME);
98
        //this.systemMetadataListener = systemMetadataListener;
99
        //this.mNode = new MNode(buildMNBaseURL());
100
        try {
101
            waitingTime = Settings.getConfiguration().getInt(WAITIMEPOPERTYNAME);
102
            maxAttempts = Settings.getConfiguration().getInt(MAXATTEMPTSPROPERTYNAME);
103
        } catch (Exception e) {
104
            log.warn("IndexGenerator.constructor - couldn't read the waiting time or maxattempts from the metacat.properties file since : "+e.getMessage()+". Default values will be used");
105
            waitingTime = WAITTIME;
106
            maxAttempts = MAXWAITNUMBER;
107
        }
108
    }
109
    
110
    /**
111
     * Build the index for all documents in Metacat without overwriting.
112
     * @throws SolrServerException 
113
     * @throws ServiceFailure 
114
     * @throws NotImplemented 
115
     * @throws NotAuthorized 
116
     * @throws InvalidToken 
117
     * @throws InvalidRequest 
118
     * @throws IndexEventLogException 
119
     * @throws IllegalAccessException 
120
     * @throws InstantiationException 
121
     * @throws ClassNotFoundException 
122
     */
123
    /*public void indexAll() throws InvalidRequest, InvalidToken, NotAuthorized, 
124
                            NotImplemented, ServiceFailure, SolrServerException, FileNotFoundException, ClassNotFoundException, InstantiationException, IllegalAccessException, IndexEventLogException {
125
        boolean force = false;
126
        indexAll(force);
127
    }*/
128
    
129
    /**
130
     * Build the index for all documents.
131
     * @throws SolrServerException 
132
     * @throws ServiceFailure 
133
     * @throws NotImplemented 
134
     * @throws NotAuthorized 
135
     * @throws InvalidToken 
136
     * @throws InvalidRequest 
137
     * @throws IndexEventLogException 
138
     * @throws IllegalAccessException 
139
     * @throws InstantiationException 
140
     * @throws ClassNotFoundException 
141
     */
142
    public void indexAll() throws InvalidRequest, InvalidToken,
143
                NotAuthorized, NotImplemented, ServiceFailure, SolrServerException, FileNotFoundException, ClassNotFoundException, InstantiationException, IllegalAccessException, IndexEventLogException {
144
        Date since = null;
145
        Date until = null;
146
        index(since, until);
147
    }
148
    
149
    /**
150
     * Build the index for the docs which have been modified since the specified date.
151
     * @param since
152
     * @throws SolrServerException 
153
     * @throws ServiceFailure 
154
     * @throws NotImplemented 
155
     * @throws NotAuthorized 
156
     * @throws InvalidToken 
157
     * @throws InvalidRequest 
158
     * @throws IndexEventLogException 
159
     * @throws IllegalAccessException 
160
     * @throws InstantiationException 
161
     * @throws ClassNotFoundException 
162
     */
163
    public void index(Date since) throws InvalidRequest, InvalidToken, 
164
                    NotAuthorized, NotImplemented, ServiceFailure, SolrServerException, FileNotFoundException, ClassNotFoundException, InstantiationException, IllegalAccessException, IndexEventLogException {
165
        Date until = null;
166
        index(since, until);
167
    }
168
    
169
    /**
170
     *  Build the index for the docs which have been modified between the specified date.s
171
     * @param since
172
     * @param until
173
     * @throws SolrServerException 
174
     * @throws ServiceFailure 
175
     * @throws NotImplemented 
176
     * @throws NotAuthorized 
177
     * @throws InvalidToken 
178
     * @throws InvalidRequest 
179
     * @throws FileNotFoundException 
180
     * @throws IndexEventLogException 
181
     * @throws IllegalAccessException 
182
     * @throws InstantiationException 
183
     * @throws ClassNotFoundException 
184
     */
185
    public void index(Date since, Date until) throws SolrServerException, InvalidRequest, 
186
                                                InvalidToken, NotAuthorized, NotImplemented, ServiceFailure, FileNotFoundException, ClassNotFoundException, InstantiationException, IllegalAccessException, IndexEventLogException {
187
        Date processedDate = null;
188
        List<String> solrIds = null;
189
        initSystemMetadataMap();
190
        initObjectPathMap();
191
        List[] metacatIds = getMetacatIds(since, until);
192
        List<String> otherMetacatIds = metacatIds[FIRST];
193
        List<String> resourceMapIds =  metacatIds[SECOND];
194
        
195
        //figure out the procesedDate by comparing the last element of otherMetacatIds and resourceMapIds.
196
        Date latestOtherId = null;
197
        if (otherMetacatIds != null && !otherMetacatIds.isEmpty()) {
198
            int size = otherMetacatIds.size();
199
            String id = otherMetacatIds.get(size-1);
200
            SystemMetadata sysmeta = getSystemMetadata(id);
201
            latestOtherId = sysmeta.getDateSysMetadataModified();
202
        }
203
        Date latestResourceId = null;
204
        if (resourceMapIds != null && !resourceMapIds.isEmpty()) {
205
            int size = resourceMapIds.size();
206
            String id = resourceMapIds.get(size-1);
207
            SystemMetadata sysmeta = getSystemMetadata(id);
208
            latestResourceId = sysmeta.getDateSysMetadataModified();
209
        }
210
        if(latestOtherId != null && latestResourceId != null && latestOtherId.getTime() > latestResourceId.getTime()) {
211
            processedDate = latestOtherId;
212
        } else if (latestOtherId != null && latestResourceId != null && latestOtherId.getTime()  <= latestResourceId.getTime()) {
213
            processedDate = latestResourceId;
214
        } else if (latestOtherId == null && latestResourceId != null) {
215
            processedDate = latestResourceId;
216
        } else if (latestOtherId != null && latestResourceId == null) {
217
            processedDate = latestOtherId;
218
        }
219
        
220
        //add the failedPids 
221
        List<IndexEvent> failedEvents = EventlogFactory.createIndexEventLog().getEvents(null, null, null, null);
222
        List<String> failedOtherIds = new ArrayList<String>();
223
        List<String> failedResourceMapIds = new ArrayList<String>();
224
        if(failedEvents != null) {
225
            for(IndexEvent event : failedEvents) {
226
            	String id = event.getIdentifier().getValue();
227
                SystemMetadata sysmeta = getSystemMetadata(id);
228
                if(sysmeta != null && !sysmeta.getArchived()) {
229
                    ObjectFormatIdentifier formatId =sysmeta.getFormatId();
230
                    if(formatId != null && formatId.getValue() != null && resourceMapNamespaces != null && isResourceMap(formatId)) {
231
                        failedResourceMapIds.add(id);
232
                    } else {
233
                        failedOtherIds.add(id);
234
                    }
235
                }
236
            }
237
        }
238
        
239
        if(!failedOtherIds.isEmpty()) {
240
            failedOtherIds.addAll(otherMetacatIds);
241
        } else {
242
            failedOtherIds = otherMetacatIds;
243
        }
244
        
245
        if(!failedResourceMapIds.isEmpty()) {
246
            failedResourceMapIds.addAll(resourceMapIds);
247
        } else {
248
            failedResourceMapIds = resourceMapIds;
249
        }
250
        
251
        log.info("the metacat ids (exception resource map -----------------------------"+failedOtherIds);
252
        log.info("the metacat resroucemap ids -----------------------------"+failedResourceMapIds);
253
        index(failedOtherIds);
254
        index(failedResourceMapIds);
255
       
256
        //record the timed index.
257
        if(processedDate != null) {
258
            EventlogFactory.createIndexEventLog().setLastProcessDate(processedDate);
259
        }
260
        
261
    }
262
    
263
    /*
264
     * Doing index
265
     */
266
    private void index(List<String> metacatIds) {
267
        if(metacatIds != null) {
268
            for(String metacatId : metacatIds) {
269
                if(metacatId != null) {
270
                        try {
271
                            generateIndex(metacatId);
272
                        } catch (Exception e) {
273
                            log.error("IndexGenerator.index - Metacat Index couldn't generate the index for the id - "+metacatId+" because "+e.getMessage());
274
                        }
275
                        
276
                   
277
                }
278
            }
279
        }
280
    }
281
    
282
    public void run() {
283
        /*IndexEvent event = new IndexEvent();
284
        event.setDate(Calendar.getInstance().getTime());
285
        event.setType(IndexEvent.STARTTIMEDINDEX);
286
        event.setDescription("Start the timed index job");
287
        try {
288
            EventlogFactory.createIndexEventLog().write(event);
289
        } catch (Exception e) {
290
            log.error("IndexGenerator.run - IndexEventLog can't log the timed indexing start event :"+e.getMessage());
291
        }*/
292
        try {
293
            Date since = EventlogFactory.createIndexEventLog().getLastProcessDate();
294
            index(since);
295
        } catch (InvalidRequest e) {
296
            // TODO Auto-generated catch block
297
            //e.printStackTrace();
298
            log.error("IndexGenerator.run - Metadata-Index couldn't generate indexes for those documents which haven't been indexed : "+e.getMessage());
299
        } catch (InvalidToken e) {
300
            // TODO Auto-generated catch block
301
            //e.printStackTrace();
302
            log.error("IndexGenerator.run - Metadata-Index couldn't generate indexes for those documents which haven't been indexed : "+e.getMessage());
303
        } catch (NotAuthorized e) {
304
            // TODO Auto-generated catch block
305
            //e.printStackTrace();
306
        } catch (NotImplemented e) {
307
            // TODO Auto-generated catch block
308
            //e.printStackTrace();
309
            log.error("IndexGenerator.run - Metadata-Index couldn't generate indexes for those documents which haven't been indexed : "+e.getMessage());
310
        } catch (ServiceFailure e) {
311
            // TODO Auto-generated catch block
312
            //e.printStackTrace();
313
            log.error("IndexGenerator.run - Metadata-Index couldn't generate indexes for those documents which haven't been indexed : "+e.getMessage());
314
        } catch (SolrServerException e) {
315
            // TODO Auto-generated catch block
316
            //e.printStackTrace();
317
            log.error("IndexGenerator.run - Metadata-Index couldn't generate indexes for those documents which haven't been indexed : "+e.getMessage());
318
        } catch (FileNotFoundException e) {
319
            log.error("IndexGenerator.run - Metadata-Index couldn't generate indexes for those documents which haven't been indexed : "+e.getMessage());
320
        }
321
        /*event.setDate(Calendar.getInstance().getTime());
322
        event.setType(IndexEvent.FINISHTIMEDINDEX);
323
        event.setDescription("Finish the timed index job");
324
        try {
325
            EventlogFactory.createIndexEventLog().write(event);
326
        } catch (Exception e) {
327
            log.error("IndexGenerator.run - IndexEventLog can't log the timed indexing finish event :"+e.getMessage());
328
        }*/ catch (ClassNotFoundException e) {
329
            // TODO Auto-generated catch block
330
            log.error("IndexGenerator.run - Metadata-Index couldn't generate indexes for those documents which haven't been indexed : "+e.getMessage());
331
        } catch (InstantiationException e) {
332
            // TODO Auto-generated catch block
333
            log.error("IndexGenerator.run - Metadata-Index couldn't generate indexes for those documents which haven't been indexed : "+e.getMessage());
334
        } catch (IllegalAccessException e) {
335
            // TODO Auto-generated catch block
336
            log.error("IndexGenerator.run - Metadata-Index couldn't generate indexes for those documents which haven't been indexed : "+e.getMessage());
337
        } catch (IndexEventLogException e) {
338
            // TODO Auto-generated catch block
339
            log.error("IndexGenerator.run - Metadata-Index couldn't generate indexes for those documents which haven't been indexed : "+e.getMessage());
340
        }
341
    }
342
    
343
    /*
344
     * Get the indexed ids list from the solr server.
345
     * An empty list will be returned if there is no ids.
346
     */
347
    private List<String> getSolrDocIds() throws SolrServerException {
348
        List<String> ids = solrIndex.getSolrIds();
349
        return ids;
350
    }
351
    
352
    /*
353
     * Get an array of the list of ids of the metacat which has the systemmetadata modification in the range.
354
     * 
355
     * If since and util are null, it will return all of them.
356
     * The first element of the list is the ids except the resource map. The second elements of the list is the ids of the resource map.
357
     * The reason to split them is when we index the resource map, we need the index of the documents in the resource map ready.
358
     * The last element in the each list has the latest SystemMetadata modification date. But they are not sorted.
359
     */
360
    private List[] getMetacatIds(Date since, Date until) throws InvalidRequest, 
361
                        InvalidToken, NotAuthorized, NotImplemented, ServiceFailure, FileNotFoundException {
362
        
363
        List<String> resourceMapIds = new ArrayList();
364
        List<String> otherIds = new ArrayList();
365
        List[] ids = new List[2];
366
        ids[FIRST]= otherIds;
367
        ids[SECOND] = resourceMapIds;
368
        ISet<Identifier> metacatIds = DistributedMapsFactory.getIdentifiersSet();
369
        Date otherPreviousDate = null;
370
        Date resourceMapPreviousDate = null;
371
        if(metacatIds != null) {
372
            for(Identifier identifier : metacatIds) {
373
                if(identifier != null && identifier.getValue() != null && !identifier.getValue().equals("")) {
374
                    SystemMetadata sysmeta = getSystemMetadata(identifier.getValue());
375
                    if(sysmeta != null && !sysmeta.getArchived()) {
376
                        ObjectFormatIdentifier formatId =sysmeta.getFormatId();
377
                        //System.out.println("the object format id is "+formatId.getValue());
378
                        //System.out.println("the ============ resourcMapNamespaces"+resourceMapNamespaces);
379
                        boolean correctTimeRange = false;
380
                        Date sysDate = sysmeta.getDateSysMetadataModified();
381
                        if(since == null && until == null) {
382
                            correctTimeRange = true;
383
                        } else if (since != null && until == null) {
384
                            if(sysDate.getTime() >= since.getTime()) {
385
                                correctTimeRange = true;
386
                            }
387
                        } else if (since == null && until != null) {
388
                            if(sysDate.getTime() <= until.getTime()) {
389
                                correctTimeRange = true;
390
                            }
391
                        } else if (since != null && until != null) {
392
                            if(sysDate.getTime() >= since.getTime() && sysDate.getTime() <= until.getTime()) {
393
                                correctTimeRange = true;
394
                            }
395
                        }
396
                        if(correctTimeRange && formatId != null && formatId.getValue() != null && resourceMapNamespaces != null && isResourceMap(formatId)) {
397
                            //for the resource map
398
                            if(!resourceMapIds.isEmpty()) {
399
                                if(sysDate.getTime() > resourceMapPreviousDate.getTime()) {
400
                                    resourceMapIds.add(identifier.getValue());//append to the end of the list if current is later than the previous one
401
                                } else {
402
                                    int size = resourceMapIds.size();//
403
                                    resourceMapIds.add(size -1, identifier.getValue());//keep the previous one at the end of the list.
404
                                }
405
                            } else {
406
                                resourceMapIds.add(identifier.getValue());
407
                            }
408
                            resourceMapPreviousDate = sysDate;
409
                        } else {
410
                            if(!otherIds.isEmpty()) {
411
                                if(sysDate.getTime() > otherPreviousDate.getTime()) {
412
                                    otherIds.add(identifier.getValue());
413
                                } else {
414
                                    int size = otherIds.size();
415
                                    otherIds.add(size-1, identifier.getValue());
416
                                }
417
                            } else {
418
                                otherIds.add(identifier.getValue());
419
                            }
420
                            otherPreviousDate = sysDate;
421
                        }
422
                        
423
                    }
424
                }
425
            }
426
        }
427
        return ids;
428
    }
429
    
430
    /*
431
     * If the specified ObjectFormatIdentifier is a resrouce map namespace.
432
     */
433
    public static boolean isResourceMap(ObjectFormatIdentifier formatId) {
434
        boolean isResourceMap = false;
435
        if(formatId != null && resourceMapNamespaces != null) {
436
            for(String namespace : resourceMapNamespaces) {
437
                if(namespace != null && formatId.getValue() != null && !formatId.getValue().trim().equals("") && formatId.getValue().equals(namespace)) {
438
                    isResourceMap = true;
439
                    break;
440
                }
441
            }
442
        }
443
        return isResourceMap;
444
    }
445
    
446
   
447
    
448
    /*
449
     * Generate index for the id.
450
     */
451
    private void generateIndex(String id) throws Exception {
452
        if(id != null)  {
453
                SystemMetadata sysmeta = getSystemMetadata(id);
454
                //only update none-archived id.
455
                if(sysmeta != null && !sysmeta.getArchived()) {
456
                        InputStream data = getDataObject(id);
457
                        Identifier obsolete = sysmeta.getObsoletes();
458
                        List<String> obsoleteChain = null;
459
                        if(obsolete != null) {
460
                            obsoleteChain = getObsoletes(id);
461
                        } 
462
                        solrIndex.update(id, obsoleteChain, sysmeta, data);
463
                } else {
464
                    throw new Exception("IndexGenerator.generate - there is no found SystemMetadata associated with the id "+id);
465
                }
466
           
467
        }
468
    }
469
    
470
    /*
471
     * Initialize the system metadata map
472
     */
473
    private void initSystemMetadataMap() throws FileNotFoundException, ServiceFailure{
474
        int times = 0;
475
        if(systemMetadataMap == null) {
476
            systemMetadataMap = DistributedMapsFactory.getSystemMetadataMap();
477
            /*while(true) {
478
                try {
479
                    systemMetadataMap = DistributedMapsFactory.getSystemMetadataMap();
480
                    break;
481
                } catch (FileNotFoundException e) {
482
                    throw e;
483
                } catch (ServiceFailure e) {
484
                    if(times <= maxAttempts) {
485
                        log.warn("IndexGenerator.initSystemMetadataMap - the hazelcast service is not ready : "
486
                                         +e.getMessage()+"\nWe will try to access it "+waitingTime/1000+" seconds later ");
487
                        try {
488
                            Thread.sleep(waitingTime);
489
                        } catch (Exception ee) {
490
                            log.warn("IndexGenerator.initSystemMetadataMap - the thread can't sleep for "+waitingTime/1000+" seconds to wait the hazelcast service");
491
                        }
492
                       
493
                    } else {
494
                        throw new ServiceFailure("0000", "IndexGenerator.initSystemMetadataMap - the hazelcast service is not ready even though Metacat-index wailted for "+maxAttempts*waitingTime/1000+" seconds. We can't get the system metadata from it and the building index can't happen this time");
495
                    }
496
                }
497
                times++;
498
            }*/
499
        }
500
    }
501
    
502
    /*
503
     * We should call this method after calling initSystemMetadataMap since this method doesn't have the mechanism to wait the readiness of the hazelcast service
504
     */
505
    private void initObjectPathMap() throws FileNotFoundException, ServiceFailure {
506
        if(objectPathMap == null) {
507
            objectPathMap = DistributedMapsFactory.getObjectPathMap();
508
        }
509
    }
510
    /**
511
     * Get an InputStream as the data object for the specific pid.
512
     * @param pid
513
     * @return
514
     * @throws FileNotFoundException
515
     */
516
    private InputStream getDataObject(String pid) throws FileNotFoundException {
517
        Identifier identifier = new Identifier();
518
        identifier.setValue(pid);
519
        String objectPath = objectPathMap.get(identifier);
520
        InputStream data = null;
521
        data = new FileInputStream(objectPath);
522
        return data;
523

    
524
    }
525
    
526
    /**
527
     * Get the SystemMetadata for the specified id from the distributed Map.
528
     * The null maybe is returned if there is no system metadata found.
529
     * @param id  the specified id.
530
     * @return the SystemMetadata associated with the id.
531
     */
532
    private SystemMetadata getSystemMetadata(String id) {
533
        SystemMetadata metadata = null;
534
        if(systemMetadataMap != null && id != null) {
535
            Identifier identifier = new Identifier();
536
            identifier.setValue(id);
537
            metadata = systemMetadataMap.get(identifier);
538
        }
539
        return metadata;
540
    }
541
    
542
    /**
543
     * Get the obsoletes chain of the specified id. The returned list doesn't include
544
     * the specified id itself. The newer version has the lower index number in the list.
545
     * Empty list will be returned if there is no document to be obsoleted by this id.
546
     * @param id
547
     * @return
548
     */
549
    private List<String> getObsoletes(String id) {
550
        List<String> obsoletes = new ArrayList<String>();
551
        while (id != null) {
552
            SystemMetadata metadata = getSystemMetadata(id);
553
            id = null;//set it to be null in order to stop the while loop if the id can't be assinged to a new value in the following code.
554
            if(metadata != null) {
555
                Identifier identifier = metadata.getObsoletes();
556
                if(identifier != null && identifier.getValue() != null && !identifier.getValue().trim().equals("")) {
557
                    obsoletes.add(identifier.getValue());
558
                    id = identifier.getValue();
559
                } 
560
            } 
561
        }
562
        return obsoletes;
563
    }
564
    
565
    /**
566
     * Overwrite and do nothing
567
     */
568
    public boolean cancel() {
569
        return true;
570
    }
571

    
572
}
(3-3/6)