001/** 002 * Copyright 2015 DuraSpace, Inc. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.fcrepo.kernel.impl; 017 018import static java.lang.System.currentTimeMillis; 019import static java.util.UUID.randomUUID; 020import static org.fcrepo.kernel.Transaction.State.COMMITED; 021import static org.fcrepo.kernel.Transaction.State.DIRTY; 022import static org.fcrepo.kernel.Transaction.State.NEW; 023import static org.fcrepo.kernel.Transaction.State.ROLLED_BACK; 024 025import java.util.Calendar; 026import java.util.Date; 027 028import javax.jcr.RepositoryException; 029import javax.jcr.Session; 030 031import org.fcrepo.kernel.Transaction; 032import org.fcrepo.kernel.exception.RepositoryRuntimeException; 033 034/** 035 * A Fedora Transaction wraps a JCR session with some expiration logic. 036 * Whenever the transaction's session is requested, the expiration is extended 037 * 038 * @author bbpennel 039 */ 040public class TransactionImpl implements Transaction { 041 042 // the default timeout is 3 minutes 043 public static final long DEFAULT_TIMEOUT = 3L * 60L * 1000L; 044 045 public static final String TIMEOUT_SYSTEM_PROPERTY = "fcrepo.transactions.timeout"; 046 047 private final Session session; 048 049 private final String id; 050 051 private final String userName; 052 053 private final Date created; 054 055 private final Calendar expires; 056 057 private State state = NEW; 058 059 /** 060 * Create a transaction for the given Session 061 * @param session the given session 062 * @param userName the user name 063 */ 064 065 public TransactionImpl(final Session session, final String userName) { 066 super(); 067 this.session = session; 068 this.created = new Date(); 069 this.id = randomUUID().toString(); 070 this.expires = Calendar.getInstance(); 071 this.updateExpiryDate(); 072 this.userName = userName; 073 } 074 075 /* (non-Javadoc) 076 * @see org.fcrepo.kernel.Transaction#getSession() 077 */ 078 @Override 079 public Session getSession() { 080 updateExpiryDate(); 081 return TxAwareSession.newInstance(session, id); 082 } 083 084 /* (non-Javadoc) 085 * @see org.fcrepo.kernel.Transaction#getCreated() 086 */ 087 @Override 088 public Date getCreated() { 089 return new Date(created.getTime()); 090 } 091 092 /* (non-Javadoc) 093 * @see org.fcrepo.kernel.Transaction#getId() 094 */ 095 @Override 096 public String getId() { 097 return id; 098 } 099 100 /* (non-Javadoc) 101 * @see org.fcrepo.kernel.Transaction#getState() 102 */ 103 @Override 104 public State getState() throws RepositoryException { 105 if (this.session != null && this.session.hasPendingChanges()) { 106 return DIRTY; 107 } 108 return state; 109 } 110 111 /* (non-Javadoc) 112 * @see org.fcrepo.kernel.Transaction#getExpires() 113 */ 114 @Override 115 public Date getExpires() { 116 return expires.getTime(); 117 } 118 119 /* (non-Javadoc) 120 * @see org.fcrepo.kernel.Transaction#commit(org.fcrepo.kernel.services.VersionService) 121 */ 122 @Override 123 public void commit() { 124 125 try { 126 this.session.save(); 127 this.state = COMMITED; 128 this.expire(); 129 } catch (final RepositoryException e) { 130 throw new RepositoryRuntimeException(e); 131 } 132 } 133 134 /* (non-Javadoc) 135 * @see org.fcrepo.kernel.Transaction#expire() 136 */ 137 @Override 138 public void expire() { 139 this.session.logout(); 140 this.expires.setTimeInMillis(currentTimeMillis()); 141 } 142 143 /* (non-Javadoc) 144 * @see org.fcrepo.kernel.Transaction#isAssociatedWithUser() 145 */ 146 @Override 147 public boolean isAssociatedWithUser(final String userName) { 148 boolean associatedWith = false; 149 if (this.userName == null) { 150 if (userName == null) { 151 associatedWith = true; 152 } 153 } else { 154 associatedWith = this.userName.equals(userName); 155 } 156 return associatedWith; 157 } 158 159 /* (non-Javadoc) 160 * @see org.fcrepo.kernel.Transaction#rollback() 161 */ 162 @Override 163 public void rollback() { 164 this.state = ROLLED_BACK; 165 try { 166 this.session.refresh(false); 167 } catch (final RepositoryException e) { 168 throw new RepositoryRuntimeException(e); 169 } 170 this.expire(); 171 } 172 173 /* (non-Javadoc) 174 * @see org.fcrepo.kernel.Transaction#updateExpiryDate() 175 */ 176 @Override 177 public void updateExpiryDate() { 178 long duration; 179 if (System.getProperty(TIMEOUT_SYSTEM_PROPERTY) != null) { 180 duration = 181 Long.parseLong(System.getProperty(TIMEOUT_SYSTEM_PROPERTY)); 182 } else { 183 duration = DEFAULT_TIMEOUT; 184 } 185 this.expires.setTimeInMillis(currentTimeMillis() + duration); 186 } 187}