[JBossWS] - Message faults not signed
by mimra
We have a project running on JBoss 4.2.0 (JBossWS 1.2.1.GA) which exposes an EJB3 web service like:
| @Stateless
| @WebService(wsdlLocation="META-INF/wsdl/LovWS.wsdl", targetNamespace = "http://rep.oio.dk/wmdata.dk/as2007/schemas/2006/11/20/")
| @SOAPBinding(style = SOAPBinding.Style.DOCUMENT)
| @HandlerChain(file = "resource://META-INF/ServerHandlers.xml", name = "SecureHandlerChain")
| @WebContext(contextRoot="/as2007/facade")
| public class LovWS extends WSBean {
| .
| .
| .
| @WebMethod()
| @WebResult(name="resultat")
| public LovType hentLov(@WebParam(name="Kode") String kode) throws WSException{
| if ("".equals(kode)){
| throw new WSException(165,"Kode argumentet er tomt");
| }
| .
| .
| .
| }
| }
|
Now if the request to the web service is successful, the response is singed as expected.
However, if any exception is thrown and a SOAP fault is returned, then the SOAP body is not signed.
Is this expected behavior? Is there any way to get JBossWS to also sign the SOAP faults?
Best regards
Michael
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4136642#4136642
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4136642
18 years, 1 month
[JBossCache] - Re: FetchInMemoryState && InitialStateRetrievalTimeout
by manik.surtani@jboss.com
Preload specifies which Fqns to preload from a cache loader, regardless of whether you are refereing to a ClusteredCacheLoader or a local persistence engine such as a JDBCCacheLoader. Also, preload allows you to be more fine-grained with what is preloaded, e.g.,
| <preload>/catalog, /users, /countryCodes</preload>
|
fetchPersistentState, on the other hand, is a flag that is only used with fetchImMemoryState. If the latter is true and you are retrieving all the state from a neighbouring cache in startup, state in any cache loader marked with fetchPersistentState set to true will be retrieved as well.
So, it's not mutually exclusive, and in fact pertains to different functions altogether. Hope this makes sense...
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4136636#4136636
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4136636
18 years, 1 month
[JBoss Portal] - PortletRequest.USER_INFO returns nothing
by rob_gar_esp
Hi,
I'm trying to retrieve user information from the PortletRequest.USER_INFO attribute, however it returns nothing all the time. The complete snippet is:
protected void doView(RenderRequest rRequest, RenderResponse rResponse) throws PortletException, IOException, UnavailableException {
|
| Map userInfo = (Map)rRequest.getAttribute(PortletRequest.USER_INFO);
| Set<String> keys = null;
| if (userInfo!=null) {
| keys = userInfo.keySet();
| logger.info("userInfo.size()=" + userInfo.size() );
| } else {
| logger.info("user info is null");
| }
| if (keys!=null){
| for (String key : keys) {
| logger.info("These are the keys: " + key );
| }
| for (String key : keys) {
| String[] arr = (String[])userInfo.get(key);
| for(int i=0;i<arr.length;i++){
| logger.info("Param: " + key + ", value[" + i + "]= " + arr);
| }
| }
| }
My portlet.xml contains:
<user-attribute>
| <description>User Name</description>
| <name>user.name</name>
| </user-attribute>
| <user-attribute>
| <description>User Id</description>
| <name>user.id</name>
| </user-attribute>
Also, the users in the admin console have basic information such as names, timezone, languagel locale and the rest of the properties, but it just does not work.
What's wrong?
Thanks in advanced
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4136620#4136620
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4136620
18 years, 1 month
[JBoss jBPM] - Problem with Timer execution. process classloader can't find
by rayun
Hi,
I have a problem with the execution of an action for my timers.
I am using JBPM 3.2.2 with Tomcat and try to execute a process with a timer on 2 tasks in a fork.
The part of the process which give me troubles is the following :
| <fork name="fork1">
| <transition name="To client" to="Client validation"></transition>
| <transition name="To broker" to="Broker validation"></transition>
| </fork>
| <task-node name="Client validation">
| <task name="client complete and validate informations" swimlane="client">
| <timer name="reminder1" duedate="30 seconds">
| <action name="Send a time-out notice for client" class="common.processhandlers.DueDateHandler"></action>
| </timer>
| </task>
| <transition name="Client informations completed" to="join1"></transition>
| </task-node>
| <task-node name="Broker validation">
| <task name="broker complete and validate informations" swimlane="broker">
| <timer name="reminder2" duedate="30 seconds">
| <action name="Send a time-out notice for broker" class="common.processhandlers.DueDateHandler"></action>
| </timer>
| </task>
| <transition name="Broker informations completed" to="join1"></transition>
| </task-node>
| <join name="join1">
| <transition name="All informations available" to="end"></transition>
| </join>
|
The class DueDateHandler i try to execute in both timer is in the sources of the web application executing the process and do nothing but displaying a message.
When i try to execute this process and the duedate for the timers expire, i get the following Error :
| ERROR - def.AbstractFlushingEventListener - 301 - Could not synchronize database state with session
| org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [org.jbpm.job.Timer#21383]
| at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1765)
| at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2407)
| at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2307)
| at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2607)
| at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:92)
| at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
| at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:234)
| at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:142)
| at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
| at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
| at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
| at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
| at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
| at org.jbpm.persistence.db.DbPersistenceService.commit(DbPersistenceService.java:256)
| at org.jbpm.persistence.db.DbPersistenceService.close(DbPersistenceService.java:214)
| at org.jbpm.svc.Services.close(Services.java:225)
| at org.jbpm.JbpmContext.close(JbpmContext.java:139)
| at org.jbpm.job.executor.JobExecutorThread.acquireJobs(JobExecutorThread.java:144)
| at org.jbpm.job.executor.JobExecutorThread.run(JobExecutorThread.java:58)
| INFO - db.DbPersistenceService - 258 - optimistic locking failed
| INFO - svc.Services - 229 - problem closing service 'persistence': optimistic locking failed
| WARN - StatefulPersistenceContext.ProxyWarnLog - 615 - Narrowing proxy to class org.jbpm.graph.node.TaskNode - this operation breaks ==
| WARN - StatefulPersistenceContext.ProxyWarnLog - 615 - Narrowing proxy to class org.jbpm.graph.node.TaskNode - this operation breaks ==
| ERROR - instantiation.Delegation - 142 - couldn't load delegation class 'common.processhandlers.DueDateHandler'
| java.lang.ClassNotFoundException: class 'common.processhandlers.DueDateHandler' could not be found by the process classloader
| at org.jbpm.instantiation.ProcessClassLoader.findClass(ProcessClassLoader.java:118)
| at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
| at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
| at org.jbpm.instantiation.Delegation.instantiate(Delegation.java:140)
| at org.jbpm.instantiation.Delegation.getInstance(Delegation.java:125)
| at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
| at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
| at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
| at java.lang.reflect.Method.invoke(Method.java:597)
| at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
| at org.jbpm.instantiation.Delegation$$EnhancerByCGLIB$$87bad03b.getInstance(<generated>)
| at org.jbpm.graph.def.Action.execute(Action.java:121)
| at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
| at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
| at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
| at java.lang.reflect.Method.invoke(Method.java:597)
| at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
| at org.jbpm.graph.def.Action$$EnhancerByCGLIB$$322143d.execute(<generated>)
| at org.jbpm.graph.def.GraphElement.executeAction(GraphElement.java:264)
| at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
| at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
| at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
| at java.lang.reflect.Method.invoke(Method.java:597)
| at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
| at org.jbpm.taskmgmt.def.Task$$EnhancerByCGLIB$$b38133b8.executeAction(<generated>)
| at org.jbpm.job.Timer.execute(Timer.java:56)
| at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
| at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
| at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
| at java.lang.reflect.Method.invoke(Method.java:597)
| at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
| at org.jbpm.job.Job$$EnhancerByCGLIB$$7970239a.execute(<generated>)
| at org.jbpm.job.executor.JobExecutorThread.executeJob(JobExecutorThread.java:164)
| at org.jbpm.job.executor.JobExecutorThread.run(JobExecutorThread.java:64)
| ERROR - instantiation.Delegation - 165 - couldn't instantiate delegation class 'common.processhandlers.DueDateHandler'
| java.lang.NullPointerException
| at org.jbpm.instantiation.FieldInstantiator.newInstance(FieldInstantiator.java:105)
| at org.jbpm.instantiation.FieldInstantiator.instantiate(FieldInstantiator.java:48)
| at org.jbpm.instantiation.Delegation.instantiate(Delegation.java:163)
| at org.jbpm.instantiation.Delegation.getInstance(Delegation.java:125)
| at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
| at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
| at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
| at java.lang.reflect.Method.invoke(Method.java:597)
| at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
| at org.jbpm.instantiation.Delegation$$EnhancerByCGLIB$$87bad03b.getInstance(<generated>)
| at org.jbpm.graph.def.Action.execute(Action.java:121)
| at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
| at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
| at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
| at java.lang.reflect.Method.invoke(Method.java:597)
| at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
| at org.jbpm.graph.def.Action$$EnhancerByCGLIB$$322143d.execute(<generated>)
| at org.jbpm.graph.def.GraphElement.executeAction(GraphElement.java:264)
| at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
| at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
| at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
| at java.lang.reflect.Method.invoke(Method.java:597)
| at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
| at org.jbpm.taskmgmt.def.Task$$EnhancerByCGLIB$$b38133b8.executeAction(<generated>)
| at org.jbpm.job.Timer.execute(Timer.java:56)
| at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
| at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
| at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
| at java.lang.reflect.Method.invoke(Method.java:597)
| at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
| at org.jbpm.job.Job$$EnhancerByCGLIB$$7970239a.execute(<generated>)
| at org.jbpm.job.executor.JobExecutorThread.executeJob(JobExecutorThread.java:164)
| at org.jbpm.job.executor.JobExecutorThread.run(JobExecutorThread.java:64)
| ERROR - def.GraphElement - 275 - action threw exception: null
| java.lang.NullPointerException
| at org.jbpm.graph.def.Action.execute(Action.java:122)
| at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
| at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
| at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
| at java.lang.reflect.Method.invoke(Method.java:597)
| at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
| at org.jbpm.graph.def.Action$$EnhancerByCGLIB$$322143d.execute(<generated>)
| at org.jbpm.graph.def.GraphElement.executeAction(GraphElement.java:264)
| at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
| at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
| at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
| at java.lang.reflect.Method.invoke(Method.java:597)
| at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
| at org.jbpm.taskmgmt.def.Task$$EnhancerByCGLIB$$b38133b8.executeAction(<generated>)
| at org.jbpm.job.Timer.execute(Timer.java:56)
| at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
| at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
| at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
| at java.lang.reflect.Method.invoke(Method.java:597)
| at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
| at org.jbpm.job.Job$$EnhancerByCGLIB$$7970239a.execute(<generated>)
| at org.jbpm.job.executor.JobExecutorThread.executeJob(JobExecutorThread.java:164)
| at org.jbpm.job.executor.JobExecutorThread.run(JobExecutorThread.java:64)
| WARN - job.Timer - 62 - timer action threw exception
| org.jbpm.graph.def.DelegationException
| at org.jbpm.graph.def.GraphElement.raiseException(GraphElement.java:387)
| at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
| at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
| at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
| at java.lang.reflect.Method.invoke(Method.java:597)
| at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
| at org.jbpm.graph.def.ProcessDefinition$$EnhancerByCGLIB$$c4ed9d31.raiseException(<generated>)
| at org.jbpm.graph.def.GraphElement.raiseException(GraphElement.java:378)
| at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
| at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
| at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
| at java.lang.reflect.Method.invoke(Method.java:597)
| at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
| at org.jbpm.graph.node.TaskNode$$EnhancerByCGLIB$$45bbca9f.raiseException(<generated>)
| at org.jbpm.graph.def.GraphElement.raiseException(GraphElement.java:378)
| at org.jbpm.graph.def.GraphElement.executeAction(GraphElement.java:281)
| at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
| at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
| at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
| at java.lang.reflect.Method.invoke(Method.java:597)
| at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
| at org.jbpm.taskmgmt.def.Task$$EnhancerByCGLIB$$b38133b8.executeAction(<generated>)
| at org.jbpm.job.Timer.execute(Timer.java:56)
| at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
| at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
| at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
| at java.lang.reflect.Method.invoke(Method.java:597)
| at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
| at org.jbpm.job.Job$$EnhancerByCGLIB$$7970239a.execute(<generated>)
| at org.jbpm.job.executor.JobExecutorThread.executeJob(JobExecutorThread.java:164)
| at org.jbpm.job.executor.JobExecutorThread.run(JobExecutorThread.java:64)
| Caused by: java.lang.NullPointerException
| at org.jbpm.graph.def.Action.execute(Action.java:122)
| at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
| at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
| at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
| at java.lang.reflect.Method.invoke(Method.java:597)
| at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
| at org.jbpm.graph.def.Action$$EnhancerByCGLIB$$322143d.execute(<generated>)
| at org.jbpm.graph.def.GraphElement.executeAction(GraphElement.java:264)
| ... 15 more
|
The class loader won't find the action to execute for the timers while the class is present in the application.
I tried many things but couldn't find a solution to this problem.
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4136618#4136618
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4136618
18 years, 1 month
[Installation, Configuration & DEPLOYMENT] - Re: java.lang.NoSuchMethodException: org.jboss.resource.adap
by cpnehete
Hi Jaikiran,
Please find code for debuggable statement class below,
And I think i didn't change any jar file.
Please do the needful.
|
| package com.work.net;
|
| import java.io.InputStream;
| import java.io.Reader;
| import java.lang.reflect.InvocationTargetException;
| import java.lang.reflect.Method;
| import java.math.BigDecimal;
| import java.net.URL;
| import java.sql.Blob;
| import java.sql.Clob;
| import java.sql.Connection;
| import java.sql.ParameterMetaData;
| import java.sql.PreparedStatement;
| import java.sql.Ref;
| import java.sql.ResultSet;
| import java.sql.ResultSetMetaData;
| import java.sql.SQLException;
| import java.sql.SQLWarning;
| import java.sql.Time;
| import java.sql.Timestamp;
| import java.util.Calendar;
| import java.util.StringTokenizer;
|
|
| public class DebuggableStatement implements PreparedStatement {
|
| private PreparedStatement ps; //preparedStatement being proxied for.
| private String sql; //original statement going to database.
| private String filteredSql;
| //statement filtered for rogue '?' that are not bind variables.
| private DebugObject[] variables; //array of bind variables
| private SqlFormatter formatter; //format for dates
| private long startTime; //time that statement began execution
| private long executeTime; //time elapsed while executing statement
| private DebugLevel debugLevel; //level of debug
|
|
| protected DebuggableStatement(
| Connection con,
| String sqlStatement,
| SqlFormatter formatter,
| DebugLevel debugLevel)
| throws SQLException {
| //set values for member variables
| this.ps = con.prepareStatement(sqlStatement);
| this.sql = sqlStatement;
| this.debugLevel = debugLevel;
| this.formatter = formatter;
|
| //see if there are any '?' in the statement that are not bind variables
| //and filter them out.
| boolean isString = false;
| char[] sqlString = sqlStatement.toCharArray();
| for (int i = 0; i < sqlString.length; i++) {
| if (sqlString == '\'')
| isString = !isString;
| //substitute the ? with an unprintable character if the ? is in a
| //string.
| if (sqlString == '?' && isString)
| sqlString = '\u0007';
| }
| filteredSql = new String(sqlString);
|
| //find out how many variables are present in statement.
| int count = 0;
| int index = -1;
| while ((index = filteredSql.indexOf("?", index + 1)) != -1) {
| count++;
| }
|
| //show how many bind variables found
| if (debugLevel == DebugLevel.VERBOSE)
| System.out.println("count= " + count);
|
| //create array for bind variables
| variables = new DebugObject[count];
|
| }
|
| /**
| * Facade for PreparedStatement
| */
| public void addBatch() throws SQLException {
| ps.addBatch();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public void addBatch(String sql) throws SQLException {
| ps.addBatch();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public void cancel() throws SQLException {
| ps.cancel();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public void clearBatch() throws SQLException {
| ps.clearBatch();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public void clearParameters() throws SQLException {
| ps.clearParameters();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public void clearWarnings() throws SQLException {
| ps.clearWarnings();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public void close() throws SQLException {
| ps.close();
| }
|
| /**
| * Executes query and Calculates query execution time if DebugLevel = VERBOSE
| * @return results of query
| */
| public boolean execute() throws SQLException {
| //execute query
| Boolean results = null;
| try {
| results = (Boolean) executeVerboseQuery("execute", null);
| }
| catch (SQLException sqle) {
| throw sqle;
| }
| catch (Exception e) {
| e.printStackTrace();
| throw new SQLException("Could not execute sql command");
| }
| return results.booleanValue();
| }
|
| /**
| * This method is only here for convenience. If a different sql string is executed
| * than was passed into Debuggable, unknown results will occur.
| * Executes query and Calculates query execution time if DebugLevel = VERBOSE
| * @param sql should be same string that was passed into Debuggable
| * @return results of query
| */
| public boolean execute(String sql) throws SQLException {
| //execute query
| Boolean results = null;
| try {
| results =
| (Boolean) executeVerboseQuery("execute",
| new Class[] { sql.getClass()});
| }
| catch (SQLException sqle) {
| throw sqle;
| }
| catch (Exception e) {
| e.printStackTrace();
| throw new SQLException("Could not execute sql command");
| }
| return results.booleanValue();
| }
|
| /**
| * Executes query and Calculates query execution time if DebugLevel = VERBOSE
| * @return results of query
| */
| public int[] executeBatch() throws SQLException {
| //execute query
| int[] results = null;
| try {
| results = (int[]) executeVerboseQuery("executeBatch", null);
| }
| catch (SQLException sqle) {
| throw sqle;
| }
| catch (Exception e) {
| e.printStackTrace();
| throw new SQLException("Could not execute sql command");
| }
| return results;
| }
|
| /**
| * Executes query and Calculates query execution time if DebugLevel = VERBOSE
| * @return results of query
| */
| public ResultSet executeQuery() throws SQLException {
| //execute query
| ResultSet results = null;
| try {
| results = (ResultSet) executeVerboseQuery("executeQuery", null);
| }
| catch (SQLException sqle) {
| throw sqle;
| }
| catch (Exception e) {
| e.printStackTrace();
| throw new SQLException("Could not execute sql command");
| }
| return results;
| }
|
| /**
| * This method is only here for convenience. If a different sql string is executed
| * than was passed into Debuggable, unknown results will occur.
| * Executes query and Calculates query execution time if DebugLevel = VERBOSE
| * @param sql should be same string that was passed into Debuggable
| * @return results of query
| */
| public ResultSet executeQuery(String sql) throws SQLException {
| //execute query
| ResultSet results = null;
| try {
| results =
| (ResultSet) executeVerboseQuery("executeQuery",
| new Class[] { sql.getClass()});
| }
| catch (SQLException sqle) {
| throw sqle;
| }
| catch (Exception e) {
| e.printStackTrace();
| throw new SQLException("Could not execute sql command");
| }
| return results;
| }
|
| /**
| * Executes query and Calculates query execution time if DebugLevel = VERBOSE
| * @return results of query
| */
| public int executeUpdate() throws SQLException {
| //execute query
| Integer results = null;
| try {
| results = (Integer) executeVerboseQuery("executeUpdate", null);
| }
| catch (SQLException sqle) {
| throw sqle;
| }
| catch (Exception e) {
| e.printStackTrace();
| throw new SQLException("Could not execute sql command");
| }
| return results.intValue();
| }
|
| /**
| * This method is only here for convenience. If a different sql string is executed
| * than was passed into Debuggable, unknown results will occur.
| * Executes query and Calculates query execution time if DebugLevel = VERBOSE
| * @param sql should be same string that was passed into Debuggable
| * @return results of query
| */
| public int executeUpdate(String sql) throws SQLException {
| //execute query
| Integer results = null;
| try {
| results =
| (Integer) executeVerboseQuery("executeUpdate",
| new Class[] { sql.getClass()});
| }
| catch (SQLException sqle) {
| throw sqle;
| }
| catch (Exception e) {
| e.printStackTrace();
| throw new SQLException("Could not execute sql command");
| }
| return results.intValue();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public Connection getConnection() throws SQLException {
| return ps.getConnection();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public int getFetchDirection() throws SQLException {
| return ps.getFetchDirection();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public int getFetchSize() throws SQLException {
| return ps.getFetchSize();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public int getMaxFieldSize() throws SQLException {
| return ps.getMaxFieldSize();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public int getMaxRows() throws SQLException {
| return ps.getMaxRows();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public ResultSetMetaData getMetaData() throws SQLException {
| return ps.getMetaData();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public boolean getMoreResults() throws SQLException {
| return ps.getMoreResults();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public int getQueryTimeout() throws SQLException {
| return ps.getQueryTimeout();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public ResultSet getResultSet() throws SQLException {
| return ps.getResultSet();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public int getResultSetConcurrency() throws SQLException {
| return ps.getResultSetConcurrency();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public int getResultSetType() throws SQLException {
| return ps.getResultSetType();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public String getStatement() {
| return sql;
| }
|
| /**
| * Facade for PreparedStatement
| */
| public int getUpdateCount() throws SQLException {
| return ps.getUpdateCount();
| }
|
| /**
| * Facade for PreparedStatement
| */
| public SQLWarning getWarnings() throws SQLException {
| return ps.getWarnings();
| }
|
| /**
| * Tests Object o for parameterIndex (which parameter is being set) and places
| * object in array of variables.
| * @param parameterIndex which PreparedStatement parameter is being set.
| * Sequence begins at 1.
| * @param o Object being stored as parameter
| * @exception Thrown if index exceeds number of variables.
| */
| private void saveObject(int parameterIndex, Object o)
| throws ParameterIndexOutOfBoundsException {
| if (parameterIndex > variables.length)
| throw new ParameterIndexOutOfBoundsException(
| "Parameter index of "
| + parameterIndex
| + " exceeds actual parameter count of "
| + variables.length);
|
| variables[parameterIndex - 1] = new DebugObject(o);
| }
|
| /**
| Adds name of the Array's internal class type(by using x.getBaseTypeName())
| to the debug String. If x is null, NULL is added to debug String.
| @param i index of parameter
| @param x parameter Object
| */
| public void setArray(int i, java.sql.Array x) throws SQLException {
| saveObject(i, x);
| ps.setArray(i, x);
| }
|
| /**
| Debug string prints NULL if InputStream is null, or adds "stream length = " + length
| */
| public void setAsciiStream(int parameterIndex, InputStream x, int length)
| throws SQLException {
| saveObject(
| parameterIndex,
| (x == null ? "NULL" : "<stream length= " + length + ">"));
| ps.setAsciiStream(parameterIndex, x, length);
| }
|
| /**
| Adds BigDecimal to debug string in parameterIndex position.
| @param parameterIndex index of parameter
| @param x parameter Object
| */
| public void setBigDecimal(int parameterIndex, BigDecimal x)
| throws SQLException {
| saveObject(parameterIndex, x);
| ps.setBigDecimal(parameterIndex, x);
| }
|
| /**
| Debug string prints NULL if InputStream is null, or adds "stream length= " + length.
| @param parameterIndex index of parameter
| @param x parameter Object
| @param length length of InputStream
| */
| public void setBinaryStream(int parameterIndex, InputStream x, int length)
| throws SQLException {
| saveObject(
| parameterIndex,
| (x == null ? "NULL" : "<stream length= " + length + ">"));
| ps.setBinaryStream(parameterIndex, x, length);
| }
|
| /**
| Adds name of the object's class type(Blob) to the debug String. If
| object is null, NULL is added to debug String.
| @param parameterIndex index of parameter
| @param x parameter Object
| */
| public void setBlob(int parameterIndex, Blob x) throws SQLException {
| saveObject(parameterIndex, x);
| ps.setBlob(parameterIndex, x);
| }
|
| /**
| Adds boolean to debug string in parameterIndex position.
| @param parameterIndex index of parameter
| @param x parameter Object
| */
| public void setBoolean(int parameterIndex, boolean x) throws SQLException {
| saveObject(parameterIndex, new Boolean(x));
| ps.setBoolean(parameterIndex, x);
| }
|
| /**
| Adds byte to debug string in parameterIndex position.
| @param parameterIndex index of parameter
| @param x parameter Object
| */
| public void setByte(int parameterIndex, byte x) throws SQLException {
| saveObject(parameterIndex, new Byte(x));
| ps.setByte(parameterIndex, x);
| }
|
| /**
| Adds byte[] to debug string in parameterIndex position.
| @param parameterIndex index of parameter
| @param x parameter Object
| */
| public void setBytes(int parameterIndex, byte[] x) throws SQLException {
| saveObject(
| parameterIndex,
| (x == null ? "NULL" : "byte[] length=" + x.length));
| ps.setBytes(parameterIndex, x);
| }
|
| /**
| Debug string prints NULL if reader is null, or adds "stream length= " + length.
| @param parameterIndex index of parameter
| @param x parameter Object
| @param length length of InputStream
| */
| public void setCharacterStream(
| int parameterIndex,
| Reader reader,
| int length)
| throws SQLException {
| saveObject(
| parameterIndex,
| (reader == null ? "NULL" : "<stream length= " + length + ">"));
| ps.setCharacterStream(parameterIndex, reader, length);
| }
|
| /**
| Adds name of the object's class type(Clob) to the debug String. If
| object is null, NULL is added to debug String.
| @param parameterIndex index of parameter
| @param x parameter Object
| */
| public void setClob(int i, Clob x) throws SQLException {
| saveObject(i, x);
| ps.setClob(i, x);
| }
|
| public void setCursorName(String name) throws SQLException {
| ps.setCursorName(name);
| }
|
| /**
| Debug string displays date in YYYY-MM-DD HH24:MI:SS.# format.
| @param parameterIndex index of parameter
| @param x parameter Object
| */
| public void setDate(int parameterIndex, java.sql.Date x)
| throws SQLException {
| saveObject(parameterIndex, x);
| ps.setDate(parameterIndex, x);
| }
|
| /**
| this implementation assumes that the Date has the date, and the
| calendar has the local info. For the debug string, the cal date
| is set to the date of x. Debug string displays date in YYYY-MM-DD HH24:MI:SS.# format.
| @param parameterIndex index of parameter
| @param x parameter Object
| @param cal uses x to set time
| */
| public void setDate(int parameterIndex, java.sql.Date x, Calendar cal)
| throws SQLException {
| cal.setTime(new java.util.Date(x.getTime()));
| saveObject(parameterIndex, cal);
| ps.setDate(parameterIndex, x, cal);
| }
|
| /**
| Adds double to debug string in parameterIndex position.
| @param parameterIndex index of parameter
| @param x parameter Object
| */
| public void setDouble(int parameterIndex, double x) throws SQLException {
| saveObject(parameterIndex, new Double(x));
| ps.setDouble(parameterIndex, x);
| }
|
| /**
| * Facade for PreparedStatement
| */
| public void setEscapeProcessing(boolean enable) throws SQLException {
| ps.setEscapeProcessing(enable);
| }
|
| /**
| * Facade for PreparedStatement
| */
| public void setFormatter(SqlFormatter formatter) {
| this.formatter = formatter;
| }
|
| /**
| * Facade for PreparedStatement
| */
| public void setFetchDirection(int direction) throws SQLException {
| ps.setFetchDirection(direction);
| }
|
| /**
| * Facade for PreparedStatement
| */
| public void setFetchSize(int rows) throws SQLException {
| ps.setFetchSize(rows);
| }
|
| /**
| Adds float to debug string in parameterIndex position.
| @param parameterIndex index of parameter
| @param x parameter Object
| */
| public void setFloat(int parameterIndex, float x) throws SQLException {
| saveObject(parameterIndex, new Float(x));
| ps.setFloat(parameterIndex, x);
| }
|
| /**
| Adds int to debug string in parameterIndex position.
| @param parameterIndex index of parameter
| @param x parameter Object
| */
| public void setInt(int parameterIndex, int x) throws SQLException {
| saveObject(parameterIndex, new Integer(x));
| ps.setInt(parameterIndex, x);
| }
|
| /**
| Adds long to debug string in parameterIndex position.
| @param parameterIndex index of parameter
| @param x parameter Object
| */
| public void setLong(int parameterIndex, long x) throws SQLException {
| saveObject(parameterIndex, new Long(x));
| ps.setLong(parameterIndex, x);
| }
|
| /**
| * Facade for PreparedStatement
| */
| public void setMaxFieldSize(int max) throws SQLException {
| ps.setMaxFieldSize(max);
| }
|
| /**
| * Facade for PreparedStatement
| */
| public void setMaxRows(int max) throws SQLException {
| ps.setMaxRows(max);
| }
|
| /**
| Adds a NULL to the debug String.
| @param parameterIndex index of parameter
| @param x parameter Object
| */
| public void setNull(int parameterIndex, int sqlType) throws SQLException {
| saveObject(parameterIndex, "NULL");
| ps.setNull(parameterIndex, sqlType);
| }
|
| /**
| Adds a NULL to the debug String.
| @param parameterIndex index of parameter
| @param x parameter Object
| @param typeName type of Object
| */
| public void setNull(int parameterIndex, int sqlType, String typeName)
| throws SQLException {
| saveObject(parameterIndex, "NULL");
| ps.setNull(parameterIndex, sqlType, typeName);
| }
|
| /**
| Adds name of the object's class type to the debug String. If
| object is null, NULL is added to debug String.
| @param parameterIndex index of parameter
| @param x parameter Object
| */
| public void setObject(int parameterIndex, Object x) throws SQLException {
| saveObject(
| parameterIndex,
| (x == null ? "NULL" : x.getClass().getName()));
| ps.setObject(parameterIndex, x);
| }
|
| /**
| Adds name of the object's class type to the debug String. If
| object is null, NULL is added to debug String.
| @param parameterIndex index of parameter
| @param x parameter Object
| @param targetSqlType database type
| */
| public void setObject(int parameterIndex, Object x, int targetSqlType)
| throws SQLException {
| saveObject(
| parameterIndex,
| (x == null ? "NULL" : x.getClass().getName()));
| ps.setObject(parameterIndex, x, targetSqlType);
| }
|
| /**
| Adds name of the object's class type to the debug String. If
| object is null, NULL is added to debug String.
| @param parameterIndex index of parameter
| @param x parameter Object
| @param targetSqlType database type
| @param scale see PreparedStatement
| */
| public void setObject(
| int parameterIndex,
| Object x,
| int targetSqlType,
| int scale)
| throws SQLException {
| saveObject(
| parameterIndex,
| (x == null ? "NULL" : x.getClass().getName()));
| ps.setObject(parameterIndex, x, targetSqlType, scale);
| }
|
| /**
| * Facade for PreparedStatement
| */
| public void setQueryTimeout(int seconds) throws SQLException {
| ps.setQueryTimeout(seconds);
| }
|
| /**
| From the javadocs:
| A reference to an SQL structured type value in the database.
| A Ref can be saved to persistent storage.
| The output from this method call in DebuggableStatement is a string representation
| of the Ref object by calling the Ref object's getBaseTypeName() method.
| Again, this will only be a String representation of the actual object
| being stored in the database.
| @param i index of parameter
| @param x parameter Object
| */
|
| public void setRef(int i, Ref x) throws SQLException {
| saveObject(i, x);
| ps.setRef(i, x);
| }
|
| /**
| Adds short to debug string in parameterIndex position.
| @param parameterIndex index of parameter
| @param x parameter Object
| */
| public void setShort(int parameterIndex, short x) throws SQLException {
| saveObject(parameterIndex, new Short(x));
| ps.setShort(parameterIndex, x);
| }
|
| /**
| Adds String to debug string in parameterIndex position.
| If String is null "NULL" is inserted in debug string.
| ****note****
| In situations where a single ' is in the string being
| inserted in the database. The debug string will need to be modified to
| reflect this when running the debug statement in the database.
| @param parameterIndex index of parameter
| @param x parameter Object
| */
| public void setString(int parameterIndex, String x) throws SQLException {
| saveObject(parameterIndex, x);
| ps.setString(parameterIndex, x);
| }
|
| /**
| Debug string displays Time in HH24:MI:SS.# format.
| @param parameterIndex index of parameter
| @param x parameter Object
| */
| public void setTime(int parameterIndex, Time x) throws SQLException {
| saveObject(parameterIndex, x);
| ps.setTime(parameterIndex, x);
| }
|
| /**
| This implementation assumes that the Time object has the time and
| Calendar has the locale info. For the debug string, the cal time
| is set to the value of x. Debug string displays time in HH24:MI:SS.# format.
| @param parameterIndex index of parameter
| @param x parameter Object
| @param cal sets time based on x
| */
| public void setTime(int parameterIndex, Time x, Calendar cal)
| throws SQLException {
| cal.setTime(new java.util.Date(x.getTime()));
| saveObject(parameterIndex, cal);
| ps.setTime(parameterIndex, x, cal);
| }
|
| /**
| Debug string displays timestamp in YYYY-MM-DD HH24:MI:SS.# format.
| @param parameterIndex index of parameter
| @param x parameter Object
| */
| public void setTimestamp(int parameterIndex, Timestamp x)
| throws SQLException {
| saveObject(parameterIndex, x);
| ps.setTimestamp(parameterIndex, x);
| }
|
| /**
| This implementation assumes that the Timestamp has the date/time and
| Calendar has the locale info. For the debug string, the cal date/time
| is set to the default value of Timestamp which is YYYY-MM-DD HH24:MI:SS.#.
| Debug string displays timestamp in DateFormat.LONG format.
| @param parameterIndex index of parameter
| @param x parameter Object
| @param cal sets time based on x
| */
| public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal)
| throws SQLException {
| cal.setTime(new java.util.Date(x.getTime()));
| saveObject(parameterIndex, cal);
| ps.setTimestamp(parameterIndex, x, cal);
| }
|
| /**
| Method has been deprecated in PreparedStatement interface.
| This method is present only to satisfy interface and does
| not do anything.
| Do not use...
| */
| public void setUnicodeStream(int parameterIndex, InputStream x, int length)
| throws SQLException {
| //ps.setUnicodeStream(parameterIndex, x, length);
| }
|
| /**
| this toString is overidden to return a String representation of
| the sql statement being sent to the database. If a bind variable
| is missing then the String contains a ? + (missing variable #)
| @return the above string representation
| */
|
| public String toString() {
| StringTokenizer st = new StringTokenizer(filteredSql, "?");
| int count = 1;
| StringBuffer statement = new StringBuffer();
| while (st.hasMoreTokens()) {
| statement.append(st.nextToken());
| if (count <= variables.length) {
| if (variables[count - 1] != null
| && variables[count - 1].isValueAssigned()) {
| try {
| statement.append(
| formatter.format(variables[count - 1]));
|
| }
| catch (SQLException e) {
| statement.append("SQLException");
| }
| }
| else {
| statement.append(
| "? " + "(missing variable # " + count + " ) ");
| }
| }
| count++;
| }
| //unfilter the string in case there where rogue '?' in query string.
| char[] unfilterSql = statement.toString().toCharArray();
| for (int i = 0; i < unfilterSql.length; i++) {
| if (unfilterSql == '\u0007')
| unfilterSql = '?';
| }
|
| //return execute time
| if (debugLevel == DebugLevel.ON)
| return new String(unfilterSql);
| else
| return new String(unfilterSql)
| + System.getProperty("line.separator")
| + System.getProperty("line.separator")
| + "query executed in "
| + executeTime
| + " milliseconds"
| + System.getProperty("line.separator");
|
| }
|
| private Object executeVerboseQuery(String methodName, Class[] parameters)
| throws
| SQLException,
| NoSuchMethodException,
| InvocationTargetException,
| IllegalAccessException {
| //determine which method we have
| Method m = ps.getClass().getDeclaredMethod(methodName, parameters);
|
| /* //debug is set to on, so no times are calculated
| if (debugLevel == DebugLevel.ON)
| return m.invoke(ps,parameters);
| */
| //calculate execution time for verbose debugging
| start();
| // Object returnObject = m.invoke(ps,parameters);
| Object returnObject = null;
| if (methodName.equals("executeUpdate")) {
| int i = ps.executeUpdate();
| returnObject = new Integer(i);
| }
| else {
| returnObject = m.invoke(ps, parameters);
| }
| end();
|
| //return the executions return type
| return returnObject;
| }
|
| private void start() {
| startTime = System.currentTimeMillis();
| }
|
| private void end() {
| executeTime = System.currentTimeMillis() - startTime;
| }
|
| private class DebugObject {
| private Object debugObject;
| private SqlFormatter formatter = new OracleSqlFormatter();
| private boolean valueAssigned;
|
| public DebugObject(Object debugObject) {
| this.debugObject = debugObject;
| valueAssigned = true;
| }
|
| public Object getDebugObject() {
| return debugObject;
| }
|
| public boolean isValueAssigned() {
| return valueAssigned;
| }
|
| public String toString() {
| String a = "";
| try {
| a = formatter.format(debugObject);
| }
| catch (SQLException sqle) {
| sqle.printStackTrace();
| }
| finally {
| }
| return a;
| }
| }
|
|
| //********* New methods are implemented, because we're going to use J2SDK1.4.2 for
| //********* the Rheumatology Application, and in 1.4.2, there are following new methods
| //********* which must be implemented if we implement the PreparedStatement interface.
|
|
| /* (non-Javadoc)
| * @see java.sql.Statement#getMoreResults(int)
| */
| public boolean getMoreResults(int current) throws SQLException {
| return false;
| }
|
| /* (non-Javadoc)
| * @see java.sql.PreparedStatement#getParameterMetaData()
| */
| public ParameterMetaData getParameterMetaData() throws SQLException {
| return null;
| }
|
| /* (non-Javadoc)
| * @see java.sql.PreparedStatement#setURL(int, java.net.URL)
| */
| public void setURL(int parameterIndex, URL x) throws SQLException {
|
| }
|
| /* (non-Javadoc)
| * @see java.sql.Statement#execute(java.lang.String, int)
| */
| public boolean execute(String sql, int autoGeneratedKeys)
| throws SQLException {
| return false;
| }
|
| /* (non-Javadoc)
| * @see java.sql.Statement#execute(java.lang.String, int[])
| */
| public boolean execute(String sql, int[] columnIndexes)
| throws SQLException {
| return false;
| }
|
| /* (non-Javadoc)
| * @see java.sql.Statement#execute(java.lang.String, java.lang.String[])
| */
| public boolean execute(String sql, String[] columnNames)
| throws SQLException {
| return false;
| }
|
| /* (non-Javadoc)
| * @see java.sql.Statement#executeUpdate(java.lang.String, int)
| */
| public int executeUpdate(String sql, int autoGeneratedKeys)
| throws SQLException {
| return 0;
| }
|
| /* (non-Javadoc)
| * @see java.sql.Statement#executeUpdate(java.lang.String, int[])
| */
| public int executeUpdate(String sql, int[] columnIndexes)
| throws SQLException {
| return 0;
| }
|
| /* (non-Javadoc)
| * @see java.sql.Statement#executeUpdate(java.lang.String, java.lang.String[])
| */
| public int executeUpdate(String sql, String[] columnNames)
| throws SQLException {
| return 0;
| }
|
| /* (non-Javadoc)
| * @see java.sql.Statement#getGeneratedKeys()
| */
| public ResultSet getGeneratedKeys() throws SQLException {
| return null;
| }
|
| /* (non-Javadoc)
| * @see java.sql.Statement#getResultSetHoldability()
| */
| public int getResultSetHoldability() throws SQLException {
| return 0;
| }
|
| }
|
|
|
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4136617#4136617
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4136617
18 years, 1 month