View Javadoc

1   /*******************************************************************************
2    *  Copyright (c) 2005, 2006 Imola Informatica.
3    *  All rights reserved. This program and the accompanying materials
4    *  are made available under the terms of the LGPL License v2.1
5    *  which accompanies this distribution, and is available at
6    *  http://www.gnu.org/licenses/lgpl.html
7    *******************************************************************************/
8   /**
9    * 
10   */
11  package it.imolinfo.jbi4cics.messageformat.jdbc;
12  
13  import it.imolinfo.jbi4cics.Logger;
14  import it.imolinfo.jbi4cics.LoggerFactory;
15  import it.imolinfo.jbi4cics.connection.jdbc.util.DisconnectedCallableStatement;
16  import it.imolinfo.jbi4cics.connection.jdbc.util.DisconnectedPreparedStatement;
17  import it.imolinfo.jbi4cics.connection.jdbc.util.DisconnectedStatementFactory;
18  import it.imolinfo.jbi4cics.exception.FormatException;
19  import it.imolinfo.jbi4cics.jbi.Messages;
20  import it.imolinfo.jbi4cics.messageformat.MessageFormatter;
21  import it.imolinfo.jbi4cics.service.ServiceContext;
22  
23  import java.sql.CallableStatement;
24  import java.sql.SQLException;
25  import java.util.ArrayList;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Map;
29  
30  import org.apache.commons.beanutils.ConvertingWrapDynaBean;
31  import org.apache.commons.beanutils.DynaBean;
32  import org.apache.commons.beanutils.ResultSetDynaClass;
33  import org.apache.commons.beanutils.WrapDynaBean;
34  
35  /**
36   * @author raffaele
37   *
38   */
39  public class JdbcFormatter implements MessageFormatter {
40  
41    /**
42     * The logger for this class and its instances.
43     */
44    private static final Logger LOG
45            = LoggerFactory.getLogger(JdbcFormatter.class);
46    
47    /**
48     * The responsible to translate localized messages.
49     */
50    private static final Messages MESSAGES
51            = Messages.getMessages(JdbcFormatter.class);
52      
53    /**
54     * 
55     */
56    public JdbcFormatter() {
57      super();
58      // TODO Auto-generated constructor stub
59    }
60  
61    /**
62     * nel caso di Jdbc l'output message è un PreparedStatement o un CallableStatement con i parametri settati. Lo statement usato sarà di tipo disconnected
63     * @see it.imolinfo.jbi4cics.messageformat.MessageFormatter#mapInputBeanToInputMessage(java.lang.Object, it.imolinfo.jbi4cics.service.ServiceContext)
64     */
65    public void mapInputBeanToInputMessage(ServiceContext serviceContext) throws FormatException {
66      Object inputBean=serviceContext.getInputBean();
67      // se siamo qui il mapping descriptor deve essere di tipo JdbcBeanMappingDescriptor
68      if (!(serviceContext.getInputMappingDescriptor() instanceof JdbcStatementDescriptor)){
69        LOG.error("CIC001801_Jdbc_statement_descriptor_not_found", 
70                serviceContext.getInputMappingDescriptor().getClass());
71        throw new FormatException(MESSAGES.getString(
72                "CIC001801_Jdbc_statement_descriptor_not_found", 
73                serviceContext.getInputMappingDescriptor().getClass()));
74      }
75      JdbcStatementDescriptor jdbcStatementDescriptor=(
76              JdbcStatementDescriptor)serviceContext.getInputMappingDescriptor();
77      DisconnectedPreparedStatement statement=null;
78      // devo costruire lo statement correttamente
79      switch (jdbcStatementDescriptor.getStatementType()) {
80        case JdbcStatementDescriptor.PREPARED_STATEMENT : {
81          statement=DisconnectedStatementFactory.prepareDisconnectedStatement(
82                  jdbcStatementDescriptor.getSql());
83          break;
84        }
85        case JdbcStatementDescriptor.CALLABLE_STATEMENT : {
86          statement=DisconnectedStatementFactory.prepareDisconnectedCall(
87                  jdbcStatementDescriptor.getSql());
88          break;
89        }
90        default : throw new FormatException(MESSAGES.getString(
91                "CIC001802_Unrecognized_statement_type", 
92                jdbcStatementDescriptor.getStatementType())); 
93      }
94      Map<String, Integer> propertyNameParameterIndexMap=jdbcStatementDescriptor.getPropertyNameParameterIndexMap();
95      WrapDynaBean dynaBean=new WrapDynaBean(inputBean);
96      for (Iterator<String> i=propertyNameParameterIndexMap.keySet().iterator();i.hasNext();){
97        try {
98          String propertyName=i.next();
99          int parameterIndex=propertyNameParameterIndexMap.get(propertyName).intValue();
100         JdbcParameterDescriptor jdbcParameterDescriptor=jdbcStatementDescriptor.getParameter(parameterIndex);
101         Object value=dynaBean.get(propertyName);
102         if (jdbcStatementDescriptor.getStatementType()==JdbcStatementDescriptor.CALLABLE_STATEMENT) {
103           ((CallableStatement)statement).registerOutParameter(parameterIndex,jdbcParameterDescriptor.getSqlType());
104         }
105         statement.setObject(parameterIndex,value);
106       }
107       catch (SQLException e){
108         //TODO loggare correttamente
109         throw new FormatException(e);
110       }
111     }
112     LOG.debug("created statement: "+statement);
113     serviceContext.setInputMessage(statement);
114   }
115 
116   /**
117    * nel caso di Jdbc l'output message è la coppia CallableStatement + resultset o valore di ritorno di un update. Ad oggi non è chiaro se serva il valore di ritorno di un update
118    * Il callable statement invece serve perchè deve essere possibile estrarre eventuali parametri di ritorno
119    * @see it.imolinfo.jbi4cics.messageformat.MessageFormatter#mapOutputMessageToOutputBean(java.lang.Object, it.imolinfo.jbi4cics.service.ServiceContext)
120    */
121   public void mapOutputMessageToOutputBean(ServiceContext serviceContext) throws FormatException {
122     Object outputMessage=serviceContext.getOutputMessage();
123     // se siamo qui il mapping descriptor deve essere di tipo JdbcBeanMappingDescriptor
124     if (!(serviceContext.getOutputMappingDescriptor() instanceof JdbcBeanMappingDescriptor)){
125       LOG.error("CIC001803_Jdbc_bean_mapping_descriptor_not_found", 
126               serviceContext.getOutputMappingDescriptor().getClass());
127       throw new FormatException(MESSAGES.getString(
128               "CIC001803_Jdbc_bean_mapping_descriptor_not_found", 
129               serviceContext.getOutputMappingDescriptor().getClass()));
130     }
131     JdbcBeanMappingDescriptor jdbcBeanMappingDescriptor=(JdbcBeanMappingDescriptor)serviceContext.getOutputMappingDescriptor();
132     JdbcStatementDescriptor jdbcStatementDescriptor=jdbcBeanMappingDescriptor.getJdbcStatementDescriptor();
133     ResultSetMappingDescriptor resultSetMappingDescriptor=jdbcBeanMappingDescriptor.getResultSetMappingDescriptor();
134     // se siamo qui output message deve esseredi tipo JdbcOutputMessage
135     if (!(outputMessage instanceof JdbcOutputMessage)){
136       LOG.error("CIC001804_Jdbc_output_message_not_found", 
137               outputMessage.getClass());
138       throw new FormatException(MESSAGES.getString(
139               "CIC001804_Jdbc_output_message_not_found", 
140               outputMessage.getClass()));
141     }   
142     JdbcOutputMessage jdbcOutputMessage=(JdbcOutputMessage)outputMessage;
143     
144     // creo l'output bean
145     WrapDynaBean wrappedOutputParameterBean=null;
146     try {
147       Object beanInstance=jdbcStatementDescriptor.getBeanClass().newInstance();
148       wrappedOutputParameterBean=new ConvertingWrapDynaBean(beanInstance);
149     }
150     catch (IllegalAccessException e){
151       LOG.error(e.getMessage(), e);
152       throw new FormatException(e.getMessage(), e);
153     }
154     catch (InstantiationException e){
155       LOG.error(e.getMessage(), e);
156       throw new FormatException(e.getMessage(), e);
157     }
158     
159     //per prima cosa elaboriamo gli output parameter    
160     if (jdbcStatementDescriptor.getStatementType()==JdbcStatementDescriptor.CALLABLE_STATEMENT){
161       // in questo caso devo gestire eventuali output parameter
162       Map<String, Integer> propertyNameParameterIndexMap=jdbcStatementDescriptor.getPropertyNameParameterIndexMap();
163       DisconnectedCallableStatement disconnectedCallableStatement=(DisconnectedCallableStatement)jdbcOutputMessage.getDisconnectedSatetement();
164       for (Iterator<String> i=propertyNameParameterIndexMap.keySet().iterator();i.hasNext();){
165         try {
166           String propertyName=i.next();
167           int parameterIndex=propertyNameParameterIndexMap.get(propertyName).intValue();
168           JdbcParameterDescriptor jdbcParameterDescriptor=jdbcStatementDescriptor.getParameter(parameterIndex);
169           if (jdbcParameterDescriptor.getInOutType()==JdbcParameterDescriptor.IN_OUT_PARAMETER || jdbcParameterDescriptor.getInOutType()==JdbcParameterDescriptor.OUT_PARAMETER){
170             Object value=disconnectedCallableStatement.getObject(parameterIndex);
171             wrappedOutputParameterBean.set(propertyName,value);
172           }
173         }
174         catch (SQLException e){
175           LOG.error(e.getMessage(), e);
176           throw new FormatException(e.getMessage(), e);
177         }
178       }      
179     }
180     
181     // a questo punto devo mappare l'eventuale result set  
182     if (jdbcStatementDescriptor.getSqlType()==JdbcStatementDescriptor.SELECT_SQL){
183       List<Object> outputResultSetBeanList=new ArrayList<Object>();
184       try{
185         // costruendo con lowercase a true dovrebbe semplificare (rendere più portabile), l'unico problema si ha se una query ha due colonne 
186         // che differiscono solo per il lowercase, ma lo ritengo improbaile
187         ResultSetDynaClass resultSetDynaClass=new ResultSetDynaClass(jdbcOutputMessage.getResultSet(),true);
188         // ciclo sulle righe del result set
189         for (Iterator i=resultSetDynaClass.iterator();i.hasNext();){
190           DynaBean rowDynaBean=(DynaBean)i.next();
191           // creo l'output bean
192           WrapDynaBean wrappedOutputResultSetBean=null;
193           try {
194             Object beanInstance=resultSetMappingDescriptor.getBeanClass().newInstance();
195             wrappedOutputResultSetBean=new ConvertingWrapDynaBean(beanInstance);
196           }
197           catch (IllegalAccessException e){
198             LOG.error(e.getMessage(), e);
199             throw new FormatException(e.getMessage(), e);
200           }
201           catch (InstantiationException e){
202             LOG.error(e.getMessage(), e);
203             throw new FormatException(e.getMessage(), e);
204           }
205           // ciclo sulle colonne del result set construendo bean        
206           Map<String, String> columnNamePropertyNameMap=resultSetMappingDescriptor.getColumnNamePropertyNameMap();
207           for (Iterator<String> j=columnNamePropertyNameMap.keySet().iterator();j.hasNext();){
208             String columnName=j.next();
209             String propertyName=columnNamePropertyNameMap.get(columnName);            
210             // metto il lower case
211             Object value=rowDynaBean.get(columnName.toLowerCase());
212             wrappedOutputResultSetBean.set(propertyName,value);
213           }
214           // a questo punto il bean è completo lo aggiungo alla lista
215           outputResultSetBeanList.add(wrappedOutputResultSetBean.getInstance());
216         }      
217       }
218       catch (SQLException e){
219         LOG.error(e.getMessage(), e);
220         throw new FormatException(e.getMessage(), e);
221       }
222       //imposto il result set nella property corretta del bean contenente
223       wrappedOutputParameterBean.set(jdbcBeanMappingDescriptor.getResultSetPropertyName(),outputResultSetBeanList);
224     }
225     serviceContext.setOutputBean(wrappedOutputParameterBean.getInstance());
226   }
227 
228 }