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