001/* 002 * jPOS Project [http://jpos.org] 003 * Copyright (C) 2000-2026 jPOS Software SRL 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.jpos.q2; 020 021import org.jdom2.Element; 022import org.jpos.core.Configurable; 023import org.jpos.core.Configuration; 024import org.jpos.core.ConfigurationException; 025import org.jpos.util.*; 026 027import java.beans.BeanInfo; 028import java.beans.Introspector; 029import java.beans.PropertyDescriptor; 030import java.io.ByteArrayOutputStream; 031import java.io.Closeable; 032import java.io.PrintStream; 033import java.lang.reflect.Method; 034import java.net.URL; 035import java.util.Iterator; 036import java.util.concurrent.ScheduledThreadPoolExecutor; 037 038/** 039 * @author <a href="mailto:taherkordy@dpi2.dpi.net.ir">Alireza Taherkordi</a> 040 * @author <a href="mailto:apr@cs.com.uy">Alejandro P. Revilla</a> 041 */ 042public class QBeanSupport 043 implements QBean, QPersist, QBeanSupportMBean, Configurable 044{ 045 Element persist; 046 int state; 047 Q2 server; 048 final Object modifyLock = new Object(); 049 boolean modified; 050 String name; 051 protected Log log; 052 protected Configuration cfg; 053 protected ScheduledThreadPoolExecutor scheduledThreadPoolExecutor; 054 055 public QBeanSupport () { 056 super(); 057 setLogger (Q2.LOGGER_NAME); 058 state = -1; 059 } 060 061 @Override 062 public void setServer (Q2 server) { 063 this.server = server; 064 } 065 066 @Override 067 public Q2 getServer () { 068 return server; 069 } 070 public QFactory getFactory () { 071 return getServer().getFactory (); 072 } 073 074 @Override 075 public void setName (String name) { 076 if (this.name == null) 077 this.name = name; 078 if (log != null) 079 log.setRealm (name); 080 setModified (true); 081 } 082 083 @Override 084 public void setLogger (String loggerName) { 085 log = Log.getLog (loggerName, getClass().getName()); 086 setModified (true); 087 } 088 089 @Override 090 public void setRealm (String realm) { 091 if (log != null) 092 log.setRealm (realm); 093 } 094 095 @Override 096 public String getRealm() { 097 return log != null ? log.getRealm() : null; 098 } 099 100 @Override 101 public String getLogger () { 102 return log != null ? log.getLogger().getName() : null; 103 } 104 105 public Log getLog () { 106 return log; 107 } 108 109 @Override 110 public String getName () { 111 return name; 112 } 113 114 @Override 115 public void init () { 116 if (state == -1) { 117 setModified (false); 118 try { 119 initService(); 120 state = QBean.STOPPED; 121 } catch (Throwable t) { 122 log.warn ("init", t); 123 } 124 } 125 } 126 127 @Override 128 public synchronized void start() { 129 if (state != QBean.DESTROYED && 130 state != QBean.STOPPED && 131 state != QBean.FAILED) 132 return; 133 134 this.state = QBean.STARTING; 135 136 try { 137 startService(); 138 } catch (Throwable t) { 139 state = QBean.FAILED; 140 log.warn ("start", t); 141 return; 142 } 143 state = QBean.STARTED; 144 } 145 146 @Override 147 public synchronized void stop () { 148 if (state != QBean.STARTED) 149 return; 150 state = QBean.STOPPING; 151 try { 152 stopService(); 153 } catch (Throwable t) { 154 state = QBean.FAILED; 155 log.warn ("stop", t); 156 return; 157 } 158 state = QBean.STOPPED; 159 } 160 161 @Override 162 public void destroy () { 163 if (state == QBean.DESTROYED) 164 return; 165 if (state != QBean.STOPPED) 166 stop(); 167 168 if (scheduledThreadPoolExecutor != null) { 169 scheduledThreadPoolExecutor.shutdown(); 170 scheduledThreadPoolExecutor = null; 171 } 172 try { 173 destroyService(); 174 } 175 catch (Throwable t) { 176 log.warn ("destroy", t); 177 } 178 state = QBean.DESTROYED; 179 } 180 181 @Override 182 public int getState () { 183 return state; 184 } 185 186 @Override 187 public URL[] getLoaderURLS() { 188 return server.getLoader().getURLs(); 189 } 190 191 @Override 192 public QClassLoader getLoader() { 193 return server.getLoader(); 194 } 195 196 @Override 197 public String getStateAsString () { 198 return state >= 0 ? stateString[state] : "Unknown"; 199 } 200 201 public void setState (int state) { 202 this.state = state; 203 } 204 205 @Override 206 public void setPersist (Element persist) { 207 this.persist = persist ; 208 } 209 210 @Override 211 public Element getPersist () { 212 setModified (false); 213 return persist; 214 } 215 216 public void setModified (boolean modified) { 217 synchronized (this.modifyLock) { 218 this.modified = modified; 219 } 220 } 221 222 @Override 223 public boolean isModified () { 224 synchronized (this.modifyLock) { 225 return modified; 226 } 227 } 228 229 public boolean running () { 230 return state == QBean.STARTING || state == QBean.STARTED; 231 } 232 233 @Override 234 public void setConfiguration (Configuration cfg) 235 throws ConfigurationException 236 { 237 this.cfg = cfg; 238 } 239 public Configuration getConfiguration () { 240 return cfg; 241 } 242 243 public String getDump () { 244 if (this instanceof Loggeable) { 245 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 246 PrintStream p = new PrintStream(baos); 247 ((Loggeable)this).dump(p, ""); 248 return baos.toString(); 249 } 250 return toString(); 251 } 252 protected void initService() throws Exception {} 253 protected void startService() throws Exception {} 254 protected void stopService() throws Exception {} 255 protected void destroyService() throws Exception {} 256 257 protected synchronized ScheduledThreadPoolExecutor getScheduledThreadPoolExecutor() { 258 if (scheduledThreadPoolExecutor == null) 259 scheduledThreadPoolExecutor = ConcurrentUtil.newScheduledThreadPoolExecutor(); 260 return scheduledThreadPoolExecutor; 261 } 262 263 protected Element createElement (String name, Class mbeanClass) { 264 Element e = new Element (name); 265 Element classPath = persist != null ? 266 persist.getChild ("classpath") : null; 267 if (classPath != null) 268 e.addContent (classPath); 269 e.setAttribute ("class", getClass().getName()); 270 if (!e.getName().equals (getName ())) 271 e.setAttribute ("name", getName()); 272 String loggerName = getLogger(); 273 if (loggerName != null) 274 e.setAttribute ("logger", loggerName); 275 276 try { 277 BeanInfo info = Introspector.getBeanInfo (mbeanClass); 278 PropertyDescriptor[] desc = info.getPropertyDescriptors(); 279 for (PropertyDescriptor aDesc : desc) { 280 if (aDesc.getWriteMethod() != null) { 281 Method read = aDesc.getReadMethod(); 282 Object obj = read.invoke(this); 283 String type = read.getReturnType().getName(); 284 if ("java.lang.String".equals(type)) 285 type = null; 286 287 addAttr(e, aDesc.getName(), obj, type); 288 } 289 } 290 } catch (Exception ex) { 291 log.warn ("get-persist", ex); 292 } 293 return e; 294 } 295 protected void addAttr (Element e, String name, Object obj, String type) { 296 String value = obj == null ? "null" : obj.toString(); 297 Element attr = new Element ("attr"); 298 attr.setAttribute ("name", name); 299 if (type != null) 300 attr.setAttribute ("type", type); 301 attr.setText (value); 302 e.addContent (attr); 303 } 304 protected Iterator getAttrs () { 305 return getPersist().getChildren ("attr").iterator(); 306 } 307 protected Iterator getAttrs (String parent) { 308 return getPersist().getChild(parent). 309 getChildren("attr").iterator(); 310 } 311 protected void setAttr (Iterator attrs, String name, Object obj) { 312 String value = obj == null ? "null" : obj.toString (); 313 while (attrs.hasNext ()) { 314 Element e = (Element) attrs.next (); 315 if (name.equals (e.getAttributeValue ("name"))) { 316 e.setText(value); 317 break; 318 } 319 } 320 } 321 protected Iterator getProperties (String parent) { 322 return getPersist().getChild (parent). 323 getChildren ("property").iterator(); 324 } 325 protected void setProperty (Iterator props, String name, String value) { 326 while (props.hasNext()) { 327 Element e = (Element) props.next(); 328 if (name.equals (e.getAttributeValue ("name"))) { 329 e.setAttribute ("value", value); 330 break; 331 } 332 } 333 } 334 protected String getProperty (Iterator props, String name) { 335 while (props.hasNext()) { 336 Element e = (Element) props.next(); 337 if (name.equals (e.getAttributeValue ("name"))) { 338 return e.getAttributeValue ("value"); 339 } 340 } 341 return null; 342 } 343 protected void close (Closeable... closeables) { 344 LogEvent evt = null; 345 for (Closeable c : closeables) { 346 try { 347 c.close(); 348 } catch (Exception e) { 349 if (evt == null) 350 evt = getLog().createWarn(); 351 evt.addMessage(e); 352 } 353 } 354 if (evt != null) 355 Logger.log(evt); 356 } 357}