001: /*
002: * The contents of this file are subject to the
003: * Mozilla Public License Version 1.1 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
006: *
007: * Software distributed under the License is distributed on an "AS IS"
008: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
009: * See the License for the specific language governing rights and
010: * limitations under the License.
011: *
012: * The Initial Developer of the Original Code is Simulacra Media Ltd.
013: * Portions created by Simulacra Media Ltd are Copyright (C) Simulacra Media Ltd, 2004.
014: *
015: * All Rights Reserved.
016: *
017: * Contributor(s):
018: */
019: package org.openharmonise.rm.security.authentication;
020:
021: import java.sql.*;
022: import java.util.*;
023: import java.util.Date;
024: import java.util.logging.*;
025:
026: import org.openharmonise.commons.cache.*;
027: import org.openharmonise.commons.dsi.*;
028: import org.openharmonise.commons.dsi.dml.*;
029: import org.openharmonise.rm.DataAccessException;
030: import org.openharmonise.rm.config.*;
031: import org.openharmonise.rm.dsi.DataStoreInterfaceFactory;
032: import org.openharmonise.rm.factory.*;
033: import org.openharmonise.rm.resources.AbstractObject;
034: import org.openharmonise.rm.resources.lifecycle.*;
035: import org.openharmonise.rm.resources.users.User;
036: import org.openharmonise.rm.security.authorization.*;
037:
038: /**
039: * Implementation of <code>UserAuthenticator</code> which uses passwords
040: * held within the Harmonise system DB for authentication.
041: * Uses the <code>User</code> object to manage passwords to ensure
042: * versioning of the <code>User</code>.
043: *
044: * @author Michael Bell
045: * @version $Revision: 1.3 $
046: *
047: */
048: public class UserAuthenticatorImpl implements UserAuthenticator,
049: EditEventListener {
050:
051: public static final String PNAME_PWD_MIN_LENGTH = "PWD_MIN_LENGTH";
052: public static final String PNAME_PWD_FORCE_ALPHA_CHAR = "PWD_FORCE_ALPHA_CHAR";
053: public static final String PNAME_PWD_FORCE_NUM_CHAR = "PWD_FORCE_NUM_CHAR";
054: public static final String PNAME_PWD_FORCE_MIX_CASE = "PWD_FORCE_MIX_CASE";
055: public static final String PNAME_PWD_RETRY_LIMIT = "PWD_RETRY_LIMIT";
056: public static final String PNAME_PWD_CHANGE_PERIOD = "PWD_CHANGE_PERIOD";
057: public static final String PNAME_PWD_HIST_CHECK_SIZE = "PWD_HIST_CHECK_SIZE";
058:
059: public static final int INVALID_PWD_LENGTH = 1;
060: public static final int INVALID_PWD_NO_ALPHA = 2;
061: public static final int INVALID_PWD_NO_NUM = 3;
062: public static final int INVALID_PWD_NO_CASE_MIX = 4;
063: public static final int INVALID_PWD_REPEAT = 5;
064: public static final int INVALID_USER_STATE = 6;
065:
066: private static final String CLMN_FAIL_COUNT = "login_fail_count";
067: private static final String CLMN_PWD_CHANGE_DATE = "pwd_change_date";
068:
069: /**
070: * Logger for this class
071: */
072: private static Logger m_logger = Logger
073: .getLogger(UserAuthenticatorImpl.class.getName());
074:
075: AbstractDataStoreInterface m_dsi = null;
076:
077: private Map m_userCache = Collections
078: .synchronizedMap(new HashMap());
079: private PasswordHelper helper;
080:
081: /**
082: * Basic constructor
083: */
084: public UserAuthenticatorImpl() {
085: super ();
086: try {
087: m_dsi = DataStoreInterfaceFactory.getDataStoreInterface();
088: } catch (DataStoreException e) {
089: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
090: throw new IllegalStateException(
091: "Error obtaining datastore interface:"
092: + e.getLocalizedMessage());
093:
094: }
095: }
096:
097: public UserAuthenticatorImpl(PasswordHelper helper) {
098: this ();
099: this .helper = helper;
100: }
101:
102: /* (non-Javadoc)
103: * @see org.openharmonise.rm.security.authentication.UserAuthenticator#authenticate(org.openharmonise.rm.resources.users.User, java.lang.String)
104: */
105: public boolean authenticate(User usr, String pwd)
106: throws UserAuthenticationException {
107: boolean bAuth = false;
108:
109: if (usr != null) {
110: try {
111: AbstractDataStoreInterface dsi = DataStoreInterfaceFactory
112: .getDataStoreInterface();
113: ColumnRef failCountCol = new ColumnRef(usr
114: .getDBTableName(), CLMN_FAIL_COUNT,
115: ColumnRef.NUMBER);
116:
117: SelectStatement select = new SelectStatement();
118:
119: select.addSelectColumn(failCountCol);
120:
121: ColumnRef keyCol = usr.getInstanceColumnRef(
122: AbstractObject.ATTRIB_KEY, false);
123:
124: select.addWhereCondition(keyCol, "=", usr.getKey());
125:
126: ResultSet rs = dsi.execute(select);
127: int nFailCount = 0;
128: if (rs.next()) {
129: nFailCount = rs.getInt(1);
130: if (nFailCount < 0) {
131: nFailCount = 0;
132: }
133: }
134:
135: rs.close();
136:
137: int nFailRetryLimit = ConfigSettings.getIntProperty(
138: PNAME_PWD_RETRY_LIMIT, "-1");
139:
140: if (nFailRetryLimit > 0
141: && nFailCount >= nFailRetryLimit) {
142: if (m_logger.isLoggable(Level.FINE)) {
143: m_logger
144: .logp(
145: Level.FINE,
146: this .getClass().getName(),
147: "authenticate",
148: "Login fail limit has been reached for user "
149: + usr.getId()
150: + ", password attempt - "
151: + pwd);
152: }
153: throw new LoginRetryLimitException();
154: }
155:
156: // TODO - hand off to password comparator utility
157: bAuth = helper.compare(pwd, usr.getPassword(), usr
158: .getSalt());
159: // bAuth = usr.getPassword().equals(pwd);
160:
161: UpdateStatement update = new UpdateStatement();
162:
163: if (bAuth == true && nFailCount != 0) {
164: update.addColumnValue(failCountCol, 0);
165: update.addWhereCondition(keyCol, "=", usr.getKey());
166: dsi.execute(update);
167:
168: } else if (bAuth == false) {
169: update.addColumnValue(failCountCol, nFailCount + 1);
170: update.addWhereCondition(keyCol, "=", usr.getKey());
171: dsi.execute(update);
172: }
173:
174: if (bAuth == true) {
175: if (hasPasswordExpired(usr) == true) {
176: if (m_logger.isLoggable(Level.FINE)) {
177: m_logger.logp(Level.FINE, this .getClass()
178: .getName(), "authenticate",
179: "Password has expired for user "
180: + usr.getId()
181: + " and password " + pwd);
182: }
183: throw new PasswordExpiredException();
184: }
185: }
186: } catch (DataAccessException e) {
187: throw new UserAuthenticationException(e);
188: } catch (DataStoreException e) {
189: throw new UserAuthenticationException(e);
190: } catch (SQLException e) {
191: throw new UserAuthenticationException(e);
192: } catch (ConfigException e) {
193: throw new UserAuthenticationException(e);
194: }
195:
196: if (m_logger.isLoggable(Level.FINER)) {
197: m_logger.logp(Level.FINER, this .getClass().getName(),
198: "authenticate", "Authenticating user "
199: + usr.getId() + " with password '"
200: + pwd + "'");
201: }
202: }
203:
204: return bAuth;
205: }
206:
207: /* (non-Javadoc)
208: * @see org.openharmonise.rm.security.authentication.UserAuthenticator#setPassword(org.openharmonise.rm.resources.users.User, org.openharmonise.rm.resources.users.User, java.lang.String, java.lang.String)
209: */
210: public int setPassword(User authUsr, User pwdUsr, String authPwd,
211: String newPwd) throws UserAuthenticationException {
212: int nCode = -1;
213:
214: try {
215:
216: boolean bAuth = false;
217:
218: try {
219: bAuth = authenticate(authUsr, authPwd);
220: } catch (PasswordExpiredException exp_e) {
221: bAuth = true;
222: }
223:
224: if (bAuth == true) {
225: if (authUsr.equals(pwdUsr) == true
226: || AuthorizationValidator.isSuperUser(authUsr) == true) {
227:
228: if ((pwdUsr.isPendingVersion() == true && pwdUsr
229: .getLiveVersion() != null)
230: || pwdUsr.getPendingVersions().size() > 0) {
231: nCode = INVALID_USER_STATE;
232: } else {
233: nCode = validatePassword(pwdUsr, newPwd);
234:
235: if (nCode == PWD_OK) {
236: boolean bIsApproved = (pwdUsr.getStatus() == Status.APPROVED);
237:
238: User newPwdUsr = (User) pwdUsr
239: .createNewVersion();
240:
241: // TODO hand off to password utility to generate hash if needed
242: //newPwdUsr.setPassword(newPwd);
243: newPwdUsr.setPassword(helper
244: .getNewPassword(newPwd, pwdUsr
245: .getSalt()));
246:
247: newPwdUsr = (User) newPwdUsr.save();
248:
249: if (bIsApproved) {
250: newPwdUsr.changeStatus(Status.APPROVED);
251: }
252:
253: }
254: }
255:
256: } else {
257: nCode = AUTHENTICATION_FAIL;
258: }
259: } else {
260: nCode = AUTHENTICATION_FAIL;
261: }
262: } catch (EditException e) {
263: throw new UserAuthenticationException(
264: "Error occured while changing password", e);
265: } catch (AuthorizationException e) {
266: throw new UserAuthenticationException(
267: "Error occured while checking super user status", e);
268: } catch (DataAccessException e) {
269: throw new UserAuthenticationException(
270: "Error occured while checking user pending status",
271: e);
272: }
273:
274: return nCode;
275: }
276:
277: /* (non-Javadoc)
278: * @see org.openharmonise.rm.security.authentication.UserAuthenticator#getUser(java.lang.String, java.lang.String)
279: */
280: public User getUser(String sUser, String sPwd)
281: throws UserAuthenticationException {
282: User usr = getUser(sUser);
283:
284: try {
285: // TODO hand off to injected password comparator
286: if (helper.compare(sPwd, usr.getPassword(), usr.getSalt()) == false) {
287: usr = null;
288: }
289: // if(usr.getPassword().equals(sPwd) == false) {
290: // usr = null;
291: // }
292: } catch (DataAccessException e) {
293: throw new UserAuthenticationException(e);
294: }
295:
296: return usr;
297: }
298:
299: /**
300: * Validates password based on properties in the config settings which specify
301: * minumum length and alphanumeric requirements.
302: *
303: * @param sPassword
304: * @return
305: * @throws UserAuthenticationException
306: */
307: public int validatePassword(User usr, String sPassword)
308: throws UserAuthenticationException {
309: boolean bIsValid = true;
310: int nStatus = PWD_OK;
311:
312: try {
313: ConfigSettings config = ConfigSettings.getInstance();
314:
315: //check min length restrictions
316: int nMinLen = ConfigSettings.getIntProperty(
317: PNAME_PWD_MIN_LENGTH, "-1");
318:
319: if (nMinLen > 0 && sPassword.length() < nMinLen) {
320: bIsValid = false;
321: nStatus = INVALID_PWD_LENGTH;
322: }
323:
324: //check alpha character restrictions
325: if (bIsValid == true) {
326: boolean bAlphaReq = ConfigSettings.getBoolProperty(
327: PNAME_PWD_FORCE_ALPHA_CHAR, "false");
328: boolean bAlphaMix = ConfigSettings.getBoolProperty(
329: PNAME_PWD_FORCE_MIX_CASE, "false");
330:
331: if (bAlphaReq == true || bAlphaMix == true) {
332: boolean bHasUpperAlpha = false;
333: boolean bHasLowerAlpha = false;
334:
335: for (int i = 0; i < sPassword.length(); i++) {
336: char c = sPassword.charAt(i);
337:
338: if (Character.isLowerCase(c)) {
339: bHasLowerAlpha = true;
340: }
341:
342: if (Character.isUpperCase(c)) {
343: bHasUpperAlpha = true;
344: }
345: }
346:
347: if (bAlphaMix == true) {
348: bIsValid = bHasUpperAlpha && bHasLowerAlpha;
349:
350: if (bIsValid == false) {
351: if (bAlphaReq == true
352: && bHasLowerAlpha == false
353: && bHasLowerAlpha == false) {
354: nStatus = INVALID_PWD_NO_ALPHA;
355: } else {
356: nStatus = INVALID_PWD_NO_CASE_MIX;
357: }
358: }
359: } else {
360: bIsValid = bHasUpperAlpha || bHasLowerAlpha;
361: if (bIsValid == false) {
362: nStatus = INVALID_PWD_NO_ALPHA;
363: }
364: }
365:
366: }
367: }
368:
369: //check numeric character restrictions
370: if (bIsValid == true) {
371: boolean bNumReq = ConfigSettings.getBoolProperty(
372: PNAME_PWD_FORCE_NUM_CHAR, "false");
373:
374: if (bNumReq == true) {
375: boolean bHasNum = false;
376: for (int i = 0; i < sPassword.length()
377: && bHasNum == false; i++) {
378: char c = sPassword.charAt(i);
379:
380: if (Character.isDigit(c)) {
381: bHasNum = true;
382: }
383: }
384: bIsValid = bHasNum;
385:
386: if (bIsValid == false) {
387: nStatus = INVALID_PWD_NO_NUM;
388: }
389: }
390: }
391:
392: //check for repeats
393: if (bIsValid == true) {
394: int pwdNum = ConfigSettings.getIntProperty(
395: PNAME_PWD_HIST_CHECK_SIZE, "1");
396:
397: if (sPassword.equals(usr.getPassword())) {
398: nStatus = INVALID_PWD_REPEAT;
399: bIsValid = false;
400: }
401:
402: if (pwdNum > 0 && bIsValid == true) {
403:
404: SelectStatement select = new SelectStatement();
405:
406: select.addSelectColumn(usr.getInstanceColumnRef(
407: User.TAG_PASSWORD, true));
408: ColumnRef verCol = usr.getInstanceColumnRef(
409: User.TAG_VERSION, true);
410:
411: select.addSelectColumn(verCol);
412:
413: select.addWhereCondition(usr.getInstanceColumnRef(
414: User.ATTRIB_ID, true), "=", usr.getId());
415:
416: select.setOrderBy(verCol);
417: select.setDistinct(true);
418:
419: ResultSet rs = m_dsi.execute(select);
420:
421: int i = 0;
422: boolean bFound = false;
423: while (rs.next() && i < pwdNum && bFound == false) {
424: String sOldPwd = rs.getString(1);
425:
426: if (sOldPwd.equals(sPassword) == true) {
427: bFound = true;
428: }
429:
430: i++;
431: }
432:
433: rs.close();
434:
435: if (bFound == true) {
436: nStatus = INVALID_PWD_REPEAT;
437: bIsValid = false;
438: }
439:
440: }
441: }
442:
443: } catch (ConfigException e) {
444: throw new UserAuthenticationException(e
445: .getLocalizedMessage(), e);
446: } catch (SQLException e) {
447: throw new UserAuthenticationException(e
448: .getLocalizedMessage(), e);
449: } catch (DataStoreException e) {
450: throw new UserAuthenticationException(e
451: .getLocalizedMessage(), e);
452: } catch (DataAccessException e) {
453: throw new UserAuthenticationException(e
454: .getLocalizedMessage(), e);
455: }
456:
457: if (m_logger.isLoggable(Level.FINE)) {
458: m_logger.logp(Level.FINE, this .getClass().getName(),
459: "validatePassword", "Validated password '"
460: + sPassword + "' for user " + usr.getId()
461: + ", returning status - " + nStatus);
462: }
463:
464: return nStatus;
465: }
466:
467: /* (non-Javadoc)
468: * @see org.openharmonise.rm.security.authentication.UserAuthenticator#getUser(java.lang.String)
469: */
470: public User getUser(String sUser)
471: throws UserAuthenticationException {
472: User usr = null;
473:
474: ResultSet rs = null;
475:
476: try {
477: CachePointer uptr = (CachePointer) m_userCache.get(sUser);
478:
479: if (uptr == null) {
480:
481: SelectStatement select = new SelectStatement();
482:
483: ColumnRef idCol = User.getObjectColumnRef(
484: User.TBL_USER, AbstractObject.ATTRIB_ID);
485: ColumnRef nameCol = User.getObjectColumnRef(
486: User.TBL_USER, AbstractObject.TAG_NAME);
487:
488: select.addSelectColumn(idCol);
489: select.addWhereCondition(nameCol, "=", sUser);
490:
491: rs = m_dsi.execute(select);
492:
493: if (rs.next()) {
494: int nId = rs.getInt(1);
495:
496: usr = (User) HarmoniseObjectFactory
497: .instantiateHarmoniseObject(m_dsi,
498: User.class.getName(), nId);
499: }
500:
501: if (usr != null && sUser.equals(usr.getName())) {
502: CachePointer ptr = CacheHandler.getInstance(m_dsi)
503: .getCachePointer(usr);
504: m_userCache.put(sUser, ptr);
505: } else {
506: //if user was found but cases didn't match
507: usr = null;
508: }
509: } else {
510: usr = (User) uptr.getObject();
511: }
512:
513: } catch (DataStoreException e) {
514: throw new UserAuthenticationException(e);
515: } catch (SQLException e) {
516: throw new UserAuthenticationException(e);
517: } catch (HarmoniseFactoryException e) {
518: throw new UserAuthenticationException(e);
519: } catch (CacheException e) {
520: throw new UserAuthenticationException(e);
521: } catch (DataAccessException e) {
522: throw new UserAuthenticationException(e);
523: } finally {
524: if (rs != null) {
525: try {
526:
527: rs.close();
528: } catch (SQLException sql_e) {
529: throw new UserAuthenticationException(sql_e
530: .getLocalizedMessage(), sql_e);
531: }
532: }
533: }
534:
535: return usr;
536: }
537:
538: /* (non-Javadoc)
539: * @see org.openharmonise.rm.security.authentication.UserAuthenticator#isUserLockedOut(java.lang.String)
540: */
541: public boolean isUserLockedOut(String sUserName)
542: throws UserAuthenticationException {
543: boolean bIsLockedOut = false;
544: SelectStatement select = new SelectStatement();
545:
546: ResultSet rs = null;
547: try {
548: int nFailRetryLimit = ConfigSettings.getIntProperty(
549: PNAME_PWD_RETRY_LIMIT, "-1");
550:
551: ColumnRef idCol = User.getObjectColumnRef(User.TBL_USER,
552: AbstractObject.ATTRIB_ID);
553: ColumnRef nameCol = User.getObjectColumnRef(User.TBL_USER,
554: AbstractObject.TAG_NAME);
555: ColumnRef failCountCol = new ColumnRef(User.TBL_USER,
556: CLMN_FAIL_COUNT, ColumnRef.NUMBER);
557:
558: select.addSelectColumn(idCol);
559: select.addSelectColumn(failCountCol);
560: select.addWhereCondition(nameCol, "=", sUserName);
561:
562: rs = m_dsi.execute(select);
563:
564: if (rs.next()) {
565: int nId = rs.getInt(1);
566:
567: int nFails = rs.getInt(2);
568:
569: if (nFailRetryLimit > 0 && nFails >= nFailRetryLimit) {
570: bIsLockedOut = true;
571: }
572: }
573:
574: } catch (DataStoreException e) {
575: throw new UserAuthenticationException(e
576: .getLocalizedMessage(), e);
577: } catch (SQLException e) {
578: throw new UserAuthenticationException(e
579: .getLocalizedMessage(), e);
580: } catch (ConfigException e) {
581: throw new UserAuthenticationException(e
582: .getLocalizedMessage(), e);
583: } finally {
584: if (rs != null) {
585: try {
586:
587: rs.close();
588: } catch (SQLException sql_e) {
589: throw new UserAuthenticationException(sql_e
590: .getLocalizedMessage(), sql_e);
591: }
592: }
593: }
594: return bIsLockedOut;
595: }
596:
597: /* (non-Javadoc)
598: * @see org.openharmonise.rm.security.authentication.UserAuthenticator#hasPasswordExpired(org.openharmonise.rm.resources.users.User)
599: */
600: public boolean hasPasswordExpired(User usr)
601: throws UserAuthenticationException {
602: boolean bExpired = false;
603:
604: try {
605: //check password hasn't expired
606: int nPwdExpryLimit = ConfigSettings.getIntProperty(
607: PNAME_PWD_CHANGE_PERIOD, "-1");
608:
609: m_logger.log(Level.FINE, "password change period - "
610: + nPwdExpryLimit);
611:
612: if (nPwdExpryLimit > 0) {
613: AbstractDataStoreInterface dsi = DataStoreInterfaceFactory
614: .getDataStoreInterface();
615:
616: SelectStatement exprySelect = new SelectStatement();
617:
618: ColumnRef pwdChangeCol = new ColumnRef(usr
619: .getDBTableName(), CLMN_PWD_CHANGE_DATE,
620: ColumnRef.DATE);
621: ColumnRef verDateCol = usr.getInstanceColumnRef(
622: User.TAG_VERSION_DATE, false);
623:
624: exprySelect.addSelectColumn(pwdChangeCol);
625: exprySelect.addSelectColumn(verDateCol);
626:
627: exprySelect.addWhereCondition(usr.getInstanceColumnRef(
628: AbstractObject.ATTRIB_KEY, false), "=", usr
629: .getKey());
630:
631: ResultSet expryRS = dsi.execute(exprySelect);
632: Date pwdDate = null;
633: if (expryRS.next()) {
634: pwdDate = expryRS.getDate(1);
635: if (pwdDate == null) {
636: pwdDate = expryRS.getDate(2);
637: }
638: }
639:
640: expryRS.close();
641:
642: GregorianCalendar cal = new GregorianCalendar();
643:
644: cal.setTime(pwdDate);
645:
646: cal.add(Calendar.DATE, nPwdExpryLimit);
647:
648: Date expiryDate = cal.getTime();
649:
650: Date now = new Date();
651:
652: if (m_logger.getLevel() == Level.FINE) {
653: m_logger.log(Level.FINE, "expiry - " + expiryDate
654: + ", now - " + now + ", pwd date - "
655: + pwdDate);
656: }
657:
658: bExpired = now.after(expiryDate);
659: }
660: } catch (ConfigException e) {
661: throw new UserAuthenticationException(e);
662: } catch (DataAccessException e) {
663: throw new UserAuthenticationException(e);
664: } catch (DataStoreException e) {
665: throw new UserAuthenticationException(e);
666: } catch (SQLException e) {
667: throw new UserAuthenticationException(e);
668: }
669:
670: return bExpired;
671: }
672:
673: /* (non-Javadoc)
674: * @see org.openharmonise.rm.resources.lifecycle.EditEventListener#workflowObjectSaved(org.openharmonise.rm.resources.lifecycle.EditEvent)
675: */
676: public void workflowObjectSaved(EditEvent event) {
677: User usr = (User) event.getSource();
678: User result = (User) event.getResult();
679: try {
680: //if user name has changed then remove from cache of users
681: if (usr.getName() != result.getName()) {
682: m_userCache.remove(usr.getName());
683: }
684:
685: } catch (DataAccessException e) {
686: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
687: }
688: }
689:
690: /* (non-Javadoc)
691: * @see org.openharmonise.rm.resources.lifecycle.EditEventListener#workflowObjectStatusChanged(org.openharmonise.rm.resources.lifecycle.EditEvent)
692: */
693: public void workflowObjectStatusChanged(EditEvent event) {
694:
695: }
696:
697: /* (non-Javadoc)
698: * @see org.openharmonise.rm.resources.lifecycle.EditEventListener#workflowObjectArchived(org.openharmonise.rm.resources.lifecycle.EditEvent)
699: */
700: public void workflowObjectArchived(EditEvent event) {
701: User usr = (User) event.getSource();
702:
703: try {
704: m_userCache.remove(usr.getName());
705: } catch (DataAccessException e) {
706: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
707: }
708: }
709:
710: /* (non-Javadoc)
711: * @see org.openharmonise.rm.resources.lifecycle.EditEventListener#workflowObjectReactivated(org.openharmonise.rm.resources.lifecycle.EditEvent)
712: */
713: /* (non-Javadoc)
714: * @see org.openharmonise.rm.resources.lifecycle.EditEventListener#workflowObjectReactivated(org.openharmonise.rm.resources.lifecycle.EditEvent)
715: */
716: public void workflowObjectReactivated(EditEvent event) {
717:
718: }
719:
720: /* (non-Javadoc)
721: * @see org.openharmonise.rm.resources.lifecycle.EditEventListener#workflowObjectLocked(org.openharmonise.rm.resources.lifecycle.EditEvent)
722: */
723: public void workflowObjectLocked(EditEvent event) {
724:
725: }
726:
727: /* (non-Javadoc)
728: * @see org.openharmonise.rm.resources.lifecycle.EditEventListener#workflowObjectUnlocked(org.openharmonise.rm.resources.lifecycle.EditEvent)
729: */
730: public void workflowObjectUnlocked(EditEvent event) {
731:
732: }
733:
734: }
|