View Javadoc

1   /*
2    * Licensed to the University Corporation for Advanced Internet Development, 
3    * Inc. (UCAID) under one or more contributor license agreements.  See the 
4    * NOTICE file distributed with this work for additional information regarding
5    * copyright ownership. The UCAID licenses this file to You under the Apache 
6    * License, Version 2.0 (the "License"); you may not use this file except in 
7    * compliance with the License.  You may obtain a copy of the License at
8    *
9    *    http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package edu.internet2.middleware.shibboleth.common.attribute.resolver.provider.dataConnector;
19  
20  import java.io.Serializable;
21  import java.sql.Connection;
22  import java.sql.PreparedStatement;
23  import java.sql.ResultSet;
24  import java.sql.SQLException;
25  import java.sql.Timestamp;
26  import java.sql.Types;
27  import java.util.ArrayList;
28  import java.util.List;
29  
30  import javax.sql.DataSource;
31  
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  
35  /**
36   * Represents as persistent, database-backed, store of identifiers.
37   * 
38   * The DDL for the database is
39   * 
40   * <tt>CREATE TABLE shibpid {localEntity VARCHAR NOT NULL, peerEntity VARCHAR NOT NULL, principalName VARCHAR NOT NULL, localId VARCHAR NOT NULL, persistentId VARCHAR NOT NULL, peerProvidedId VARCHAR, creationDate TIMESTAMP NOT NULL, deactivationDate TIMESTAMP}</tt>
41   * .
42   */
43  public class StoredIDStore {
44  
45      /** Class logger. */
46      private final Logger log = LoggerFactory.getLogger(StoredIDStore.class);
47  
48      /** JDBC data source for retrieving connections. */
49      private DataSource dataSource;
50  
51      /** Timeout of SQL queries in seconds. */
52      private int queryTimeout;
53  
54      /** Name of the database table. */
55      private final String table = "shibpid";
56  
57      /** Name of the local entity ID column. */
58      private final String localEntityColumn = "localEntity";
59  
60      /** Name of the peer entity ID name column. */
61      private final String peerEntityColumn = "peerEntity";
62  
63      /** Name of the principal name column. */
64      private final String principalNameColumn = "principalName";
65  
66      /** Name of the local ID column. */
67      private final String localIdColumn = "localId";
68  
69      /** Name of the persistent ID column. */
70      private final String persistentIdColumn = "persistentId";
71  
72      /** ID, provided by peer, associated with the persistent ID. */
73      private final String peerProvidedIdColumn = "peerProvidedId";
74  
75      /** Name of the creation time column. */
76      private final String createTimeColumn = "creationDate";
77  
78      /** Name of the deactivation time column. */
79      private final String deactivationTimeColumn = "deactivationDate";
80  
81      /** Partial select query for ID entries. */
82      private final String idEntrySelectSQL = "SELECT * FROM " + table + " WHERE ";
83  
84      /** SQL used to deactivate an ID. */
85      private final String deactivateIdSQL = "UPDATE " + table + " SET " + deactivationTimeColumn + "= ? WHERE "
86              + persistentIdColumn + "= ?";
87  
88      /**
89       * Constructor.
90       * 
91       * @param source datasource used to communicate with the database
92       * @param timeout SQL query timeout in seconds
93       */
94      public StoredIDStore(DataSource source, int timeout) {
95          dataSource = source;
96          queryTimeout = timeout;
97      }
98  
99      /**
100      * Gets the number of persistent ID entries for a (principal, peer, local) tuple.
101      * 
102      * @param localEntity entity ID of the ID issuer
103      * @param peerEntity entity ID of the peer the ID is for
104      * @param localId local ID part of the persistent ID
105      * 
106      * @return the number of identifiers
107      * 
108      * @throws SQLException thrown if there is a problem communication with the database
109      */
110     public int getNumberOfPersistentIdEntries(String localEntity, String peerEntity, String localId)
111             throws SQLException {
112         StringBuilder sqlBuilder = new StringBuilder();
113         sqlBuilder.append("SELECT");
114         sqlBuilder.append(" count(").append(persistentIdColumn).append(")");
115         sqlBuilder.append(" FROM ").append(table).append(" WHERE ");
116         sqlBuilder.append(localEntityColumn).append(" = ?");
117         sqlBuilder.append(" AND ");
118         sqlBuilder.append(peerEntityColumn).append(" = ?");
119         sqlBuilder.append(" AND ");
120         sqlBuilder.append(localIdColumn).append(" = ?");
121 
122         String sql = sqlBuilder.toString();
123         Connection dbConn = dataSource.getConnection();
124         try {
125             log.debug("Selecting number of persistent ID entries based on prepared sql statement: {}", sql);
126             PreparedStatement statement = dbConn.prepareStatement(sql);
127             statement.setQueryTimeout(queryTimeout);
128 
129             log.debug("Setting prepared statement parameter {}: {}", 1, localEntity);
130             statement.setString(1, localEntity);
131             log.debug("Setting prepared statement parameter {}: {}", 2, peerEntity);
132             statement.setString(2, peerEntity);
133             log.debug("Setting prepared statement parameter {}: {}", 3, localId);
134             statement.setString(3, localId);
135 
136             ResultSet rs = statement.executeQuery();
137             rs.next();
138             return rs.getInt(1);
139         } finally {
140             try {
141                 if (dbConn != null && !dbConn.isClosed()) {
142                     dbConn.close();
143                 }
144             } catch (SQLException e) {
145                 log.error("Error closing database connection", e);
146             }
147         }
148     }
149 
150     /**
151      * Gets all the persistent ID entries for a (principal, peer, local) tuple.
152      * 
153      * @param localId local ID part of the persistent ID
154      * @param peerEntity entity ID of the peer the ID is for
155      * @param localEntity entity ID of the ID issuer
156      * 
157      * @return the active identifier
158      * 
159      * @throws SQLException thrown if there is a problem communication with the database
160      */
161     public List<PersistentIdEntry> getPersistentIdEntries(String localEntity, String peerEntity, String localId)
162             throws SQLException {
163         StringBuilder sqlBuilder = new StringBuilder(idEntrySelectSQL);
164         sqlBuilder.append(localEntityColumn).append(" = ?");
165         sqlBuilder.append(" AND ").append(peerEntityColumn).append(" = ?");
166         sqlBuilder.append(" AND ").append(localIdColumn).append(" = ?");
167         String sql = sqlBuilder.toString();
168 
169         log.debug("Selecting all persistent ID entries based on prepared sql statement: {}", sql);
170 
171         Connection dbConn = dataSource.getConnection();
172         try {
173             PreparedStatement statement = dbConn.prepareStatement(sql);
174             statement.setQueryTimeout(queryTimeout);
175 
176             log.debug("Setting prepared statement parameter {}: {}", 1, localEntity);
177             statement.setString(1, localEntity);
178             log.debug("Setting prepared statement parameter {}: {}", 2, peerEntity);
179             statement.setString(2, peerEntity);
180             log.debug("Setting prepared statement parameter {}: {}", 3, localId);
181             statement.setString(3, localId);
182 
183             return buildIdentifierEntries(statement.executeQuery());
184         } finally {
185             try {
186                 if (dbConn != null && !dbConn.isClosed()) {
187                     dbConn.close();
188                 }
189             } catch (SQLException e) {
190                 log.error("Error closing database connection", e);
191             }
192         }
193     }
194 
195     /**
196      * Gets the persistent ID entry for the given ID.
197      * 
198      * @param persistentId the persistent ID
199      * 
200      * @return the ID entry for the given ID
201      * 
202      * @throws SQLException thrown if there is a problem communication with the database
203      */
204     public PersistentIdEntry getActivePersistentIdEntry(String persistentId) throws SQLException {
205         return getPersistentIdEntry(persistentId, true);
206     }
207 
208     /**
209      * Gets the persistent ID entry for the given ID.
210      * 
211      * @param persistentId the persistent ID
212      * @param onlyActiveId true if only an active ID should be returned, false if a deactivated ID may be returned
213      * 
214      * @return the ID entry for the given ID
215      * 
216      * @throws SQLException thrown if there is a problem communication with the database
217      */
218     public PersistentIdEntry getPersistentIdEntry(String persistentId, boolean onlyActiveId) throws SQLException {
219         StringBuilder sqlBuilder = new StringBuilder(idEntrySelectSQL);
220         sqlBuilder.append(persistentIdColumn).append(" = ?");
221         if (onlyActiveId) {
222             sqlBuilder.append(" AND ").append(deactivationTimeColumn).append(" IS NULL");
223         }
224         String sql = sqlBuilder.toString();
225 
226         log.debug("Selecting persistent ID entry based on prepared sql statement: {}", sql);
227 
228         Connection dbConn = dataSource.getConnection();
229         try {
230             PreparedStatement statement = dbConn.prepareStatement(sql);
231             statement.setQueryTimeout(queryTimeout);
232 
233             log.debug("Setting prepared statement parameter {}: {}", 1, persistentId);
234             statement.setString(1, persistentId);
235 
236             List<PersistentIdEntry> entries = buildIdentifierEntries(statement.executeQuery());
237 
238             if (entries == null || entries.size() == 0) {
239                 return null;
240             }
241 
242             if (entries.size() > 1) {
243                 log.warn("More than one identifier found, only the first will be used");
244             }
245 
246             return entries.get(0);
247         } finally {
248             try {
249                 if (dbConn != null && !dbConn.isClosed()) {
250                     dbConn.close();
251                 }
252             } catch (SQLException e) {
253                 log.error("Error closing database connection", e);
254             }
255         }
256     }
257 
258     public PersistentIdEntry getActivePersistentIdEntry(String localEntity, String peerEntity, String localId,
259             boolean isActive) throws SQLException {
260         StringBuilder sqlBuilder = new StringBuilder(idEntrySelectSQL);
261         sqlBuilder.append(localEntityColumn).append(" = ?");
262         sqlBuilder.append(" AND ").append(peerEntityColumn).append(" = ?");
263         sqlBuilder.append(" AND ").append(localIdColumn).append(" = ?");
264         if(isActive){
265             sqlBuilder.append(" AND ").append(deactivationTimeColumn).append(" IS NULL");
266         }else{
267             sqlBuilder.append(" AND ").append(deactivationTimeColumn).append(" IS NOT NULL");
268         }
269         String sql = sqlBuilder.toString();
270 
271         log.debug("Selecting persistent ID entry based on prepared sql statement: {}", sql);
272         Connection dbConn = dataSource.getConnection();
273         try {
274             PreparedStatement statement = dbConn.prepareStatement(sql);
275             statement.setQueryTimeout(queryTimeout);
276 
277             log.debug("Setting prepared statement parameter {}: {}", 1, localEntity);
278             statement.setString(1, localEntity);
279             log.debug("Setting prepared statement parameter {}: {}", 2, peerEntity);
280             statement.setString(2, peerEntity);
281             log.debug("Setting prepared statement parameter {}: {}", 3, localId);
282             statement.setString(3, localId);
283 
284             log.debug("Getting active persistent Id entries.");
285             List<PersistentIdEntry> entries = buildIdentifierEntries(statement.executeQuery());
286 
287             if (entries == null || entries.size() == 0) {
288                 return null;
289             }
290 
291             if (entries.size() > 1) {
292                 log.warn("More than one active identifier, only the first will be used");
293             }
294 
295             return entries.get(0);
296         } finally {
297             try {
298                 if (dbConn != null && !dbConn.isClosed()) {
299                     dbConn.close();
300                 }
301             } catch (SQLException e) {
302                 log.error("Error closing database connection", e);
303             }
304         }
305     }
306 
307     /**
308      * Gets the currently active identifier entry for a (principal, peer, local) tuple.
309      * 
310      * @param localId local ID part of the persistent ID
311      * @param peerEntity entity ID of the peer the ID is for
312      * @param localEntity entity ID of the ID issuer
313      * 
314      * @return the active identifier
315      * 
316      * @throws SQLException thrown if there is a problem communication with the database
317      */
318     public PersistentIdEntry getActivePersistentIdEntry(String localEntity, String peerEntity, String localId)
319             throws SQLException {
320         StringBuilder sqlBuilder = new StringBuilder(idEntrySelectSQL);
321         sqlBuilder.append(localEntityColumn).append(" = ?");
322         sqlBuilder.append(" AND ").append(peerEntityColumn).append(" = ?");
323         sqlBuilder.append(" AND ").append(localIdColumn).append(" = ?");
324         sqlBuilder.append(" AND ").append(deactivationTimeColumn).append(" IS NULL");
325         String sql = sqlBuilder.toString();
326 
327         log.debug("Selecting active persistent ID entry based on prepared sql statement: {}", sql);
328         Connection dbConn = dataSource.getConnection();
329         try {
330             PreparedStatement statement = dbConn.prepareStatement(sql);
331             statement.setQueryTimeout(queryTimeout);
332 
333             log.debug("Setting prepared statement parameter {}: {}", 1, localEntity);
334             statement.setString(1, localEntity);
335             log.debug("Setting prepared statement parameter {}: {}", 2, peerEntity);
336             statement.setString(2, peerEntity);
337             log.debug("Setting prepared statement parameter {}: {}", 3, localId);
338             statement.setString(3, localId);
339 
340             log.debug("Getting active persistent Id entries.");
341             List<PersistentIdEntry> entries = buildIdentifierEntries(statement.executeQuery());
342 
343             if (entries == null || entries.size() == 0) {
344                 return null;
345             }
346 
347             if (entries.size() > 1) {
348                 log.warn("More than one active identifier, only the first will be used");
349             }
350 
351             return entries.get(0);
352         } finally {
353             try {
354                 if (dbConn != null && !dbConn.isClosed()) {
355                     dbConn.close();
356                 }
357             } catch (SQLException e) {
358                 log.error("Error closing database connection", e);
359             }
360         }
361     }
362 
363     /**
364      * Gets the list of deactivated IDs for a given (principal, peer, local) tuple.
365      * 
366      * @param localId local component of the Id
367      * @param peerEntity entity ID of the peer the ID is for
368      * @param localEntity entity ID of the ID issuer
369      * 
370      * @return list of deactivated identifiers
371      * 
372      * @throws SQLException thrown if there is a problem communication with the database
373      */
374     public List<PersistentIdEntry> getDeactivatedPersistentIdEntries(String localEntity, String peerEntity,
375             String localId) throws SQLException {
376         StringBuilder sqlBuilder = new StringBuilder(idEntrySelectSQL);
377         sqlBuilder.append(localEntityColumn).append(" = ?");
378         sqlBuilder.append(" AND ").append(peerEntityColumn).append(" = ?");
379         sqlBuilder.append(" AND ").append(localIdColumn).append(" = ?");
380         sqlBuilder.append(" AND ").append(deactivationTimeColumn).append(" IS NOT NULL");
381         String sql = sqlBuilder.toString();
382 
383         log.debug("Selecting deactivated persistent ID entries based on prepared sql statement: {}", sql);
384         Connection dbConn = dataSource.getConnection();
385         try {
386             PreparedStatement statement = dbConn.prepareStatement(sql);
387             statement.setQueryTimeout(queryTimeout);
388 
389             log.debug("Setting prepared statement parameter {}: {}", 1, localEntity);
390             statement.setString(1, localEntity);
391             log.debug("Setting prepared statement parameter {}: {}", 2, peerEntity);
392             statement.setString(2, peerEntity);
393             log.debug("Setting prepared statement parameter {}: {}", 3, localId);
394             statement.setString(3, localId);
395 
396             log.debug("Getting deactivated persistent Id entries");
397             List<PersistentIdEntry> entries = buildIdentifierEntries(statement.executeQuery());
398 
399             if (entries == null || entries.size() == 0) {
400                 return null;
401             }
402 
403             return entries;
404         } finally {
405             try {
406                 if (dbConn != null && !dbConn.isClosed()) {
407                     dbConn.close();
408                 }
409             } catch (SQLException e) {
410                 log.error("Error closing database connection", e);
411             }
412         }
413     }
414 
415     /**
416      * Stores a persistent ID entry into the database.
417      * 
418      * @param entry entry to persist
419      * 
420      * @throws SQLException thrown is there is a problem writing to the database
421      */
422     public void storePersistentIdEntry(PersistentIdEntry entry) throws SQLException {
423 
424         StringBuilder sqlBuilder = new StringBuilder("INSERT INTO ");
425         sqlBuilder.append(table).append(" (");
426         sqlBuilder.append(localEntityColumn).append(", ");
427         sqlBuilder.append(peerEntityColumn).append(", ");
428         sqlBuilder.append(principalNameColumn).append(", ");
429         sqlBuilder.append(localIdColumn).append(", ");
430         sqlBuilder.append(persistentIdColumn).append(", ");
431         sqlBuilder.append(peerProvidedIdColumn).append(", ");
432         sqlBuilder.append(createTimeColumn);
433         sqlBuilder.append(") VALUES (?, ?, ?, ?, ?, ?, ?)");
434 
435         String sql = sqlBuilder.toString();
436 
437         Connection dbConn = dataSource.getConnection();
438         try {
439             log.debug("Storing persistent ID entry based on prepared sql statement: {}", sql);
440             PreparedStatement statement = dbConn.prepareStatement(sql);
441             statement.setQueryTimeout(queryTimeout);
442 
443             log.debug("Setting prepared statement parameter {}: {}", 1, entry.getLocalEntityId());
444             statement.setString(1, entry.getLocalEntityId());
445             log.debug("Setting prepared statement parameter {}: {}", 2, entry.getPeerEntityId());
446             statement.setString(2, entry.getPeerEntityId());
447             log.debug("Setting prepared statement parameter {}: {}", 3, entry.getPrincipalName());
448             statement.setString(3, entry.getPrincipalName());
449             log.debug("Setting prepared statement parameter {}: {}", 4, entry.getLocalId());
450             statement.setString(4, entry.getLocalId());
451             log.debug("Setting prepared statement parameter {}: {}", 5, entry.getPersistentId());
452             statement.setString(5, entry.getPersistentId());
453 
454             if (entry.getPeerProvidedId() == null) {
455                 log.debug("Setting prepared statement parameter {}: {}", 6, Types.VARCHAR);
456                 statement.setNull(6, Types.VARCHAR);
457             } else {
458                 log.debug("Setting prepared statement parameter {}: {}", 6, entry.getPeerProvidedId());
459                 statement.setString(6, entry.getPeerProvidedId());
460             }
461             Timestamp timestamp = new Timestamp(System.currentTimeMillis());
462             log.debug("Setting prepared statement parameter {}: {}", 7, timestamp.toString());
463             statement.setTimestamp(7, timestamp);
464 
465             statement.executeUpdate();
466         } finally {
467             try {
468                 if (dbConn != null && !dbConn.isClosed()) {
469                     dbConn.close();
470                 }
471             } catch (SQLException e) {
472                 log.error("Error closing database connection", e);
473             }
474         }
475     }
476 
477     /**
478      * Deactivates a given persistent ID.
479      * 
480      * @param persistentId ID to deactivate
481      * @param deactivation deactivation time, if null the current time is used
482      * 
483      * @throws SQLException thrown if there is a problem communication with the database
484      */
485     public void deactivatePersistentId(String persistentId, Timestamp deactivation) throws SQLException {
486         Timestamp deactivationTime = deactivation;
487         if (deactivationTime == null) {
488             deactivationTime = new Timestamp(System.currentTimeMillis());
489         }
490 
491         Connection dbConn = dataSource.getConnection();
492         try {
493             log.debug("Deactivating persistent id {} as of {}", persistentId, deactivationTime.toString());
494             PreparedStatement statement = dbConn.prepareStatement(deactivateIdSQL);
495             statement.setQueryTimeout(queryTimeout);
496             statement.setTimestamp(1, deactivationTime);
497             statement.setString(2, persistentId);
498             statement.executeUpdate();
499         } finally {
500             try {
501                 if (dbConn != null && !dbConn.isClosed()) {
502                     dbConn.close();
503                 }
504             } catch (SQLException e) {
505                 log.error("Error closing database connection", e);
506             }
507         }
508     }
509 
510     /**
511      * Builds a list of {@link PersistentIdEntry}s from a result set.
512      * 
513      * @param resultSet the result set
514      * 
515      * @return list of {@link PersistentIdEntry}s
516      * 
517      * @throws SQLException thrown if there is a problem reading the information from the database
518      */
519     protected List<PersistentIdEntry> buildIdentifierEntries(ResultSet resultSet) throws SQLException {
520         ArrayList<PersistentIdEntry> entries = new ArrayList<PersistentIdEntry>();
521 
522         PersistentIdEntry entry;
523         while (resultSet.next()) {
524             entry = new PersistentIdEntry();
525             entry.setLocalEntityId(resultSet.getString(localEntityColumn));
526             entry.setPeerEntityId(resultSet.getString(peerEntityColumn));
527             entry.setPrincipalName(resultSet.getString(principalNameColumn));
528             entry.setPersistentId(resultSet.getString(persistentIdColumn));
529             entry.setLocalId(resultSet.getString(localIdColumn));
530             entry.setPeerProvidedId(resultSet.getString(peerProvidedIdColumn));
531             entry.setCreationTime(resultSet.getTimestamp(createTimeColumn));
532             entry.setDeactivationTime(resultSet.getTimestamp(deactivationTimeColumn));
533             entries.add(entry);
534 
535             log.trace("");
536         }
537 
538         return entries;
539     }
540 
541     /** Data object representing a persistent identifier entry in the database. */
542     public class PersistentIdEntry implements Serializable {
543 
544         /** Serial version UID . */
545         private static final long serialVersionUID = -8711779466442306767L;
546 
547         /** ID of the entity that issued that identifier. */
548         private String localEntityId;
549 
550         /** ID of the entity to which the identifier was issued. */
551         private String peerEntityId;
552 
553         /** Name of the principal represented by the identifier. */
554         private String principalName;
555 
556         /** Local component portion of the persistent ID entry. */
557         private String localId;
558 
559         /** The persistent identifier. */
560         private String persistentId;
561 
562         /** ID, associated with the persistent identifier, provided by the peer. */
563         private String peerProvidedId;
564 
565         /** Time the identifier was created. */
566         private Timestamp creationTime;
567 
568         /** Time the identifier was deactivated. */
569         private Timestamp deactivationTime;
570 
571         /** Constructor. */
572         public PersistentIdEntry() {
573         }
574 
575         /**
576          * Gets the ID of the entity that issued the identifier.
577          * 
578          * @return ID of the entity that issued the identifier
579          */
580         public String getLocalEntityId() {
581             return localEntityId;
582         }
583 
584         /**
585          * Sets the ID of the entity that issued the identifier.
586          * 
587          * @param id ID of the entity that issued the identifier
588          */
589         public void setLocalEntityId(String id) {
590             localEntityId = id;
591         }
592 
593         /**
594          * Gets the ID of the entity to which the identifier was issued.
595          * 
596          * @return ID of the entity to which the identifier was issued
597          */
598         public String getPeerEntityId() {
599             return peerEntityId;
600         }
601 
602         /**
603          * Sets the ID of the entity to which the identifier was issued.
604          * 
605          * @param id ID of the entity to which the identifier was issued
606          */
607         public void setPeerEntityId(String id) {
608             peerEntityId = id;
609         }
610 
611         /**
612          * Gets the name of the principal the identifier represents.
613          * 
614          * @return name of the principal the identifier represents
615          */
616         public String getPrincipalName() {
617             return principalName;
618         }
619 
620         /**
621          * Sets the name of the principal the identifier represents.
622          * 
623          * @param name name of the principal the identifier represents
624          */
625         public void setPrincipalName(String name) {
626             principalName = name;
627         }
628 
629         /**
630          * Gets the local ID component of the persistent identifier.
631          * 
632          * @return local ID component of the persistent identifier
633          */
634         public String getLocalId() {
635             return localId;
636         }
637 
638         /**
639          * Sets the local ID component of the persistent identifier.
640          * 
641          * @param id local ID component of the persistent identifier
642          */
643         public void setLocalId(String id) {
644             localId = id;
645         }
646 
647         /**
648          * Gets the persistent identifier.
649          * 
650          * @return the persistent identifier
651          */
652         public String getPersistentId() {
653             return persistentId;
654         }
655 
656         /**
657          * Set the persistent identifier.
658          * 
659          * @param id the persistent identifier
660          */
661         public void setPersistentId(String id) {
662             persistentId = id;
663         }
664 
665         /**
666          * Gets the ID, provided by the peer, associated with this ID.
667          * 
668          * @return ID, provided by the peer, associated with this ID
669          */
670         public String getPeerProvidedId() {
671             return peerProvidedId;
672         }
673 
674         /**
675          * Sets the ID, provided by the peer, associated with this ID.
676          * 
677          * @param id ID, provided by the peer, associated with this ID
678          */
679         public void setPeerProvidedId(String id) {
680             peerProvidedId = id;
681         }
682 
683         /**
684          * Gets the time the identifier was created.
685          * 
686          * @return time the identifier was created
687          */
688         public Timestamp getCreationTime() {
689             return creationTime;
690         }
691 
692         /**
693          * Sets the time the identifier was created.
694          * 
695          * @param time time the identifier was created
696          */
697         public void setCreationTime(Timestamp time) {
698             creationTime = time;
699         }
700 
701         /**
702          * Gets the time the identifier was deactivated.
703          * 
704          * @return time the identifier was deactivated
705          */
706         public Timestamp getDeactivationTime() {
707             return deactivationTime;
708         }
709 
710         /**
711          * Sets the time the identifier was deactivated.
712          * 
713          * @param time the time the identifier was deactivated
714          */
715         public void setDeactivationTime(Timestamp time) {
716             this.deactivationTime = time;
717         }
718 
719         /** {@inheritDoc} */
720         public String toString() {
721             StringBuilder stringForm = new StringBuilder("PersistentIdEntry{");
722             stringForm.append("persistentId:").append(persistentId).append(", ");
723             stringForm.append("localEntityId:").append(localEntityId).append(", ");
724             stringForm.append("peerEntityId:").append(peerEntityId).append(", ");
725             stringForm.append("localId:").append(localId).append(", ");
726             stringForm.append("principalName:").append(principalName).append(", ");
727             stringForm.append("peerProvidedId:").append(peerProvidedId).append(", ");
728             stringForm.append("creationTime:").append(creationTime).append(", ");
729             stringForm.append("deactivationTime:").append(deactivationTime).append(", ");
730             stringForm.append("}");
731             return stringForm.toString();
732         }
733     }
734 }