001    /*
002     @license.text@ 
003     */
004    package biz.hammurapi.sql.xml;
005    
006    import java.io.ByteArrayInputStream;
007    import java.sql.ResultSet;
008    import java.sql.ResultSetMetaData;
009    import java.sql.SQLException;
010    
011    import org.w3c.dom.DOMException;
012    import org.w3c.dom.Document;
013    import org.w3c.dom.Element;
014    import org.w3c.dom.Node;
015    
016    import biz.hammurapi.CarryOverException;
017    import biz.hammurapi.config.ConfigurationException;
018    import biz.hammurapi.config.Context;
019    import biz.hammurapi.config.DomConfigFactory;
020    import biz.hammurapi.config.PropertyParser;
021    import biz.hammurapi.sql.MetadataAwareRowProcessor;
022    import biz.hammurapi.sql.SQLProcessor;
023    import biz.hammurapi.xml.dom.DOMUtils;
024    
025    
026    /**
027     * @author Pavel Vlasov
028     * @version $Revision: 1.2 $
029     */
030    public class Select extends SQLCommand implements Command {
031            
032            //      private String pageSize;
033    //      private String pageNumParameter;
034            private CompositeCommand onRow;
035            private CompositeCommand onEmptySet;
036            
037            public void configure(Node configNode, Context context) throws ConfigurationException {
038                    super.configure(configNode, context);
039                    try {
040                            Node n=DOMUtils.selectSingleNode(configNode, "on-row");
041                            if (n!=null) {
042                                    onRow=new CompositeCommand();
043                                    onRow.configure(n, context);
044                            }
045                            
046                            n=DOMUtils.selectSingleNode(configNode, "on-empty-result-set");
047                            if (n!=null) {
048                                    onEmptySet=new CompositeCommand();
049                                    onEmptySet.configure(n, context);
050                            }
051                    } catch (Exception e) {
052                            throw new ConfigurationException(e);
053                    }               
054            }
055            
056            public void execute(final Element holder, SQLProcessor pProcessor, final Context context) throws SQL2XMLException {
057                    final SQLProcessor processor = getProcessor()==null ? pProcessor : getProcessor();
058                    // TODO Paged processing
059                    try {
060                            if (parameterizer==null || parameterizer.setContext(context)) {
061                                    final Document ownerDocument = holder.getOwnerDocument();
062                                    final Element resultSetElement=ownerDocument.createElement("result-set");
063                                    holder.appendChild(resultSetElement);
064                                    if (name!=null) {
065                                            resultSetElement.setAttribute("name", name);
066                                    }
067    
068                                    processor.processSelect(
069                                                    sql,
070                                                    parameterizer,
071                                                    new MetadataAwareRowProcessor() {
072                                                            public boolean process(final ResultSet rs) throws SQLException {
073                                                                    Element rowElement=ownerDocument.createElement("row");
074                                                                    resultSetElement.appendChild(rowElement);
075                                                                    for (int i=1, j=rs.getMetaData().getColumnCount(); i<=j; i++) {
076                                                                            Element columnElement=ownerDocument.createElement("column");
077                                                                            rowElement.appendChild(columnElement);
078                                                                            columnElement.setAttribute("name", rs.getMetaData().getColumnName(i));
079                                                                            columnElement.setAttribute("type", rs.getMetaData().getColumnTypeName(i));
080                                                                            switch (rs.getMetaData().isNullable(i)) {
081                                                                                    case ResultSetMetaData.columnNoNulls:
082                                                                                            columnElement.setAttribute("nullable", "no");
083                                                                                            break;
084                                                                                    case ResultSetMetaData.columnNullable:
085                                                                                            columnElement.setAttribute("nullable", "yes");
086                                                                                            break;
087                                                                                    case ResultSetMetaData.columnNullableUnknown:
088                                                                                            columnElement.setAttribute("nullable", "unknown");
089                                                                                            break;                                                                                                                                                                          
090                                                                            }
091                                                                            String value = rs.getString(i);
092                                                                            if (value!=null) {
093                                                                                    columnElement.appendChild(ownerDocument.createTextNode(value));
094                                                                            }
095                                                                            
096                                                                    }
097                                                                    
098                                                                    try {
099                                                                            if (onRow!=null) {
100                                                                                    onRow.execute(
101                                                                                            rowElement, 
102                                                                                            processor, 
103                                                                                            new Context() {
104                                                                                                    public Object get(String name) {
105                                                                                                            //System.out.println("Context.get("+name+")");
106                                                                                                            if (Select.this.name!=null && name.startsWith(Select.this.name+".")) {
107                                                                                                                    name=name.substring(Select.this.name.length()+1);
108                                                                                                                    return findColumn(name);
109                                                                                                            } else if (name.indexOf('.')!=-1) {
110                                                                                                                    return context==null ? null : context.get(name);
111                                                                                                            } else {
112                                                                                                                    Object ret=findColumn(name);
113                                                                                                                    return ret==null ? context==null ? null : context.get(name) : ret; 
114                                                                                                            }
115                                                                                                    }
116            
117                                                                                                    /**
118                                                                                                     * @param rs
119                                                                                                     * @param name
120                                                                                                     * @return
121                                                                                                     */
122                                                                                                    private Object findColumn(String name) {
123                                                                                                            try {
124                                                                                                                    for (int i=1; i<=rs.getMetaData().getColumnCount(); i++) {
125                                                                                                                            if (name.equals(rs.getMetaData().getColumnName(i))) {
126                                                                                                                                    return rs.getObject(i);
127                                                                                                                            }
128                                                                                                                    }
129                                                                                                                    return null;
130                                                                                                            } catch (SQLException e) {
131                                                                                                                    throw new CarryOverException(e);
132                                                                                                            }
133                                                                                                    }
134                                                                                                    
135                                                                                            });
136                                                                            }
137                                                                    } catch (SQL2XMLException e) {
138                                                                            throw new CarryOverException(e);
139                                                                    }
140            
141                                                                    return true;
142                                                            }
143    
144                                                            public void processMetadata(ResultSetMetaData metadata) throws DOMException, SQLException {
145                                                                    Element metadataElement=ownerDocument.createElement("metadata");
146                                                                    resultSetElement.appendChild(metadataElement);
147                                                                    for (int i=1; i<=metadata.getColumnCount(); i++) {
148                                                                            Element columnElement=ownerDocument.createElement("column");
149                                                                            metadataElement.appendChild(columnElement);
150                                                                            columnElement.setAttribute("name", metadata.getColumnName(i));
151                                                                            columnElement.setAttribute("type", metadata.getColumnTypeName(i));
152                                                                    }
153                                                            }
154    
155                                                            public void onEmptyResultSet() throws SQLException {
156                                                                    try {
157                                                                            if (onEmptySet!=null) {
158                                                                                    onEmptySet.execute(holder, processor, context);
159                                                                            }
160                                                                    } catch (SQL2XMLException e) {
161                                                                            throw new CarryOverException(e);
162                                                                    }       
163                                                            }
164                                                    });
165                            }
166                    } catch (final SQLException e) {
167                            throw new SQL2XMLException(
168                                            new PropertyParser(
169                                                            new Context() {
170                                                                    public Object get(String name) {
171                                                                            if ("error.message".equals(name)) {
172                                                                                    return e.getMessage();
173                                                                            } else if ("error.class".equals(name)) {
174                                                                                    return e.getClass().getName();
175                                                                            } else {
176                                                                                    return context.get(name);
177                                                                            }
178                                                                    }
179                                                            }, false).parse(errorMessage), e);
180                    } catch (final CarryOverException e) {
181                            if (e.getCause() instanceof SQL2XMLException) {
182                                    throw (SQL2XMLException) e.getCause();
183                            } else {
184                                    throw new SQL2XMLException(
185                                                    new PropertyParser(
186                                                                    new Context() {
187                                                                            public Object get(String name) {
188                                                                                    if ("error.message".equals(name)) {
189                                                                                            return e.getCause().getMessage();
190                                                                                    } else if ("error.class".equals(name)) {
191                                                                                            return e.getCause().getClass().getName();
192                                                                                    } else {
193                                                                                            return context.get(name);
194                                                                                    }
195                                                                            }
196                                                                    }, false).parse(errorMessage), e.getCause());
197                            }
198                    }
199            }
200            
201            public static void main(String[] args) throws Exception {
202                    DomConfigFactory factory=new DomConfigFactory();
203                    String xml = "<query type=\"biz.hammurapi.sql.xml.Select\">" +
204                                    "<sql>select * from people where last_name=?[lastName]?</sql>" +
205                                    "</query>";
206                    Command select= (Command) factory.create(new ByteArrayInputStream(xml.getBytes()), "/query");
207                    
208            }
209    }