1 /*
2 * Copyright 2003 - 2013 The eFaps Team
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * Revision: $Rev$
17 * Last Changed: $Date$
18 * Last Changed By: $Author$
19 */
20
21 package org.efaps.db.transaction;
22
23 import javax.transaction.RollbackException;
24 import javax.transaction.SystemException;
25 import javax.transaction.xa.XAResource;
26 import javax.transaction.xa.Xid;
27
28 import org.efaps.db.Context;
29 import org.efaps.util.EFapsException;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 /**
34 * Abstract class used to given an easy interface to implemented XA resources
35 * within the eFaps application.<br/>
36 * To use the implementation of such resource, it must be called first method
37 * {@link #open}. To free a resource of using, methods {@link #commit} (if all
38 * work was OK) or {@link #abort} (if the transaction must be rolled back) must
39 * be called.
40 *
41 * @author The eFaps Team
42 * @version $Id$
43 */
44 public abstract class AbstractResource
45 implements XAResource
46 {
47 /**
48 * Logging instance used in this class.
49 */
50 private static Logger LOG = LoggerFactory.getLogger(AbstractResource.class);
51
52 /**
53 * Is set to <i>true</i> if the connection resource is already enlisted in
54 * the transaction. Otherwise the value is <i>false</i>.
55 */
56 private boolean opened = false;
57
58 /**
59 * Opens this connection resource and enlisted this resource in the
60 * transaction.
61 *
62 * @throws EFapsException if the resource is already opened or this
63 * resource could not be enlisted
64 */
65 public void open() throws EFapsException
66 {
67 AbstractResource.LOG.debug("open resource:{}", this);
68 if (this.opened) {
69 AbstractResource.LOG.error("resource already opened");
70 throw new EFapsException(AbstractResource.class, "open.AlreadyOpened");
71 }
72 try {
73 final Context context = Context.getThreadContext();
74 context.getTransaction().enlistResource(this);
75 } catch (final RollbackException e) {
76 AbstractResource.LOG.error("exception occurs while delisting in transaction, "
77 + "commit not possible", e);
78 throw new EFapsException(AbstractResource.class,
79 "open.RollbackException", e);
80 } catch (final SystemException e) {
81 AbstractResource.LOG.error("exception occurs while delisting in transaction, "
82 + "commit not possible", e);
83 throw new EFapsException(AbstractResource.class,
84 "open.SystemException", e);
85 }
86 this.opened = true;
87 }
88
89 /**
90 * Closes this connection resource and delisted this resource in the
91 * transaction. The method must be called if the transaction should be
92 * commited.
93 *
94 * @throws EFapsException if the resource is not opened or this resource
95 * could not delisted
96 */
97 public void commit() throws EFapsException
98 {
99 AbstractResource.LOG.debug("commit resource:{}", this);
100 if (!this.opened) {
101 AbstractResource.LOG.error("resource not opened, commit not possible");
102 throw new EFapsException(AbstractResource.class, "commit.NotOpened");
103 }
104 try {
105 final Context context = Context.getThreadContext();
106 context.getTransaction().delistResource(this, XAResource.TMSUCCESS);
107 } catch (final SystemException e) {
108 AbstractResource.LOG.error("exception occurs while delisting in transaction, "
109 + "commit not possible", e);
110 throw new EFapsException(AbstractResource.class, "commit.SystemException", e);
111 }
112 freeResource();
113 this.opened = false;
114 }
115
116 /**
117 * Closes this XA resource and delisted this resource in the transaction.
118 * <br/>
119 * The method must be called if the transaction should be aborted (rolled
120 * back).
121 *
122 * @throws EFapsException if the resource is not opened or this resource
123 * could not delisted
124 */
125 public void abort()
126 throws EFapsException
127 {
128 AbstractResource.LOG.debug("abort resource:{}", this);
129 if (!this.opened) {
130 throw new EFapsException(AbstractResource.class, "abort.NotOpened");
131 }
132 try {
133 final Context context = Context.getThreadContext();
134 context.getTransaction().delistResource(this, XAResource.TMFAIL);
135 context.abort();
136 } catch (final SystemException e) {
137 throw new EFapsException(AbstractResource.class, "abort.SystemException", e);
138 }
139 freeResource();
140 this.opened = false;
141 }
142
143 /**
144 * Method used to free this resource in the eFaps context object (so that
145 * the resource instance could be reused).
146 */
147 protected abstract void freeResource();
148
149 /**
150 * This is the getter method for instance variable {@link #opened}.
151 *
152 * @return <code>true</code> if this resource is open, otherwise
153 * <code>false</code> is returned.
154 * @see #opened
155 */
156 public final boolean isOpened()
157 {
158 return this.opened;
159 }
160
161 /**
162 * The method starts work on behalf of a transaction branch specified in
163 * parameter <code>_xid</code>. Normally nothing must be done, because the
164 * pre-work is already done in the contructor (and an instance of a
165 * resource is only defined for one transaction).
166 *
167 * @param _xid global transaction identifier
168 * @param _flags flags
169 */
170 public void start(final Xid _xid,
171 final int _flags)
172 {
173 AbstractResource.LOG.trace("start resource {}, flags {}" + _flags, _xid, _flags);
174 }
175
176 /**
177 * The method ends the work performed on behalf of a transaction branch.
178 * Normally nothing must be done, because an instance of a resource is only
179 * defined for one transaction.
180 *
181 * @param _xid global transaction identifier
182 * @param _flags flags
183 */
184 public void end(final Xid _xid,
185 final int _flags)
186 {
187 AbstractResource.LOG.trace("end resource {}, flags {}" + _flags, _xid, _flags);
188 }
189
190 /**
191 * The method is called from the transaction (manager) to check if the XA
192 * resource is the same as the given XA resource in the parameter
193 * <code>_xaras</code>. This is done with a string compare
194 * (method {@link String#equals(Object)}) off the
195 * {@link Object#toString()} methods of this and the XA resource in
196 * <code>_xaras</code>.
197 *
198 * @param _xares XA resource used to test if same resource
199 * @return <code>true</code> if the string compare returns that they are
200 * equal, otherwise <code>false</code> is returned
201 * @see XAResource#isSameRM(XAResource)
202 */
203 public boolean isSameRM(final XAResource _xares)
204 {
205 final boolean ret = _xares.toString().equals(toString());
206 AbstractResource.LOG.trace("is Same RM: {}", ret);
207 return ret;
208 }
209 }