1 /*
2 Copyright 2010 Ramon Servadei
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 package mirrormap.lifecycle;
17
18 import java.util.logging.Level;
19 import java.util.logging.Logger;
20
21 import mirrormap.Utils;
22
23 /**
24 * Base-class for all {@link ILifeCycle} instances.
25 *
26 * @author Ramon Servadei
27 */
28 public abstract class AbstractLifeCycle implements ILifeCycle
29 {
30 private final static Logger LOGGER =
31 Logger.getLogger(AbstractLifeCycle.class.getName());
32
33 /**
34 * The active flag. Uses the <a
35 * href="http://www.ibm.com/developerworks/java/library/j-jtp06197.html"
36 * >'cheap read-write lock'</a>
37 */
38 private volatile boolean active;
39
40 public AbstractLifeCycle()
41 {
42 super();
43 }
44
45 public final boolean isActive()
46 {
47 return this.active;
48 }
49
50 /**
51 * Overridden in subclasses to perform custom logic on activation. Any
52 * exceptions should be thrown as a {@link RuntimeException} or subclass
53 * thereof. When this method is called, the {@link #isActive()} method will
54 * return <code>true</code>.
55 */
56 protected abstract void doStart();
57
58 /**
59 * Overridden in subclasses to perform custom logic on destruction. Any
60 * exceptions should be thrown as a {@link RuntimeException} or subclass
61 * thereof.
62 */
63 protected abstract void doDestroy();
64
65 public final void start()
66 {
67 boolean start = false;
68 synchronized (this)
69 {
70 if (!isActive())
71 {
72 this.active = true;
73 start = true;
74 }
75 }
76 if (start)
77 {
78 if (LOGGER.isLoggable(Level.FINEST))
79 {
80 LOGGER.finest("Starting " + Utils.safeToString(this));
81 }
82 try
83 {
84 doStart();
85 }
86 catch (RuntimeException e)
87 {
88 Utils.logException(LOGGER, "Exception starting "
89 + Utils.safeToString(this), e);
90 throw e;
91 }
92 }
93 }
94
95 public final void destroy()
96 {
97 boolean destroy = false;
98 synchronized (this)
99 {
100 if (isActive())
101 {
102 this.active = false;
103 destroy = true;
104 }
105 }
106 if (destroy)
107 {
108 if (LOGGER.isLoggable(Level.FINEST))
109 {
110 LOGGER.finest("Destroying " + Utils.safeToString(this));
111 }
112 try
113 {
114 doDestroy();
115 }
116 catch (RuntimeException e)
117 {
118 Utils.logException(LOGGER, "Exception destroying "
119 + Utils.safeToString(this), e);
120 }
121 }
122 }
123
124 @Override
125 protected final void finalize() throws Throwable
126 {
127 super.finalize();
128 destroy();
129 }
130
131 /**
132 * Check if this instance is active.
133 *
134 * @throws IllegalStateException
135 * if this is not active
136 */
137 protected void checkActive()
138 {
139 if (!isActive())
140 {
141 throw new IllegalStateException(this + " is not active.");
142 }
143 }
144
145 @Override
146 public String toString()
147 {
148 return getClass().getSimpleName();
149 }
150 }