0001: // JdbcBeanSerializer.java
0002: // $Id: JdbcBeanSerializer.java,v 1.17 2007/02/11 18:35:38 ylafon Exp $
0003: // (c) COPYRIGHT MIT, INRIA and Keio, 2000.
0004: // Please first read the full copyright statement in file COPYRIGHT.html
0005: package org.w3c.tools.jdbc;
0006:
0007: import java.beans.BeanInfo;
0008: import java.beans.Beans;
0009: import java.beans.IntrospectionException;
0010: import java.beans.Introspector;
0011: import java.beans.PropertyChangeListener;
0012: import java.beans.PropertyChangeEvent;
0013: import java.beans.PropertyDescriptor;
0014:
0015: import java.io.IOException;
0016:
0017: import java.lang.reflect.Method;
0018: import java.lang.reflect.InvocationTargetException;
0019:
0020: import java.sql.ResultSet;
0021: import java.sql.ResultSetMetaData;
0022: import java.sql.SQLException;
0023:
0024: import java.util.Enumeration;
0025: import java.util.Hashtable;
0026: import java.util.Properties;
0027: import java.util.Vector;
0028:
0029: /**
0030: * Read <a href="http://www.w3.org/Jigsaw/Doc/Programmer/jspdb.html">http://www.w3.org/Jigsaw/Doc/Programmer/jspdb.html</a>
0031: * to know how to use this class.
0032: * @version $Revision: 1.17 $
0033: * @author Benoît Mahé (bmahe@w3.org)
0034: */
0035: public class JdbcBeanSerializer implements PropertyChangeListener {
0036:
0037: /**
0038: * Bean modified?
0039: */
0040: private boolean modified = false;
0041:
0042: /**
0043: * Our bean.
0044: */
0045: protected JdbcBeanInterface bean = null;
0046:
0047: /**
0048: * The associated JdbcBean
0049: */
0050: private JdbcBeanInterface beans[] = null;
0051:
0052: /**
0053: * INTERSECT, UNION, EXCEPT.
0054: */
0055: protected final static int NOTHING = -1;
0056: protected final static int INTERSECT = 10;
0057: protected final static int UNION = 20;
0058: protected final static int EXCEPT = 30;
0059:
0060: protected int priority[] = { NOTHING, NOTHING, NOTHING };
0061:
0062: protected JdbcBeanSerializer intersect_serializer = null;
0063: protected JdbcBeanSerializer union_serializer = null;
0064: protected JdbcBeanSerializer except_serializer = null;
0065:
0066: /**
0067: * The ResultSet
0068: */
0069: protected ResultSet result = null;
0070:
0071: /**
0072: * The tables/bean used to generate the SQL request (in the correct
0073: * order)
0074: */
0075: private Vector beantables = null;
0076:
0077: /**
0078: * The Foreign keys <(class,class), String[]>
0079: */
0080: private static Hashtable foreignKeys = new Hashtable();
0081:
0082: private void registerForeignKeys(Class beanclass1, Class beanclass2) {
0083: Integer key = new Integer(beanclass1.hashCode()
0084: & beanclass2.hashCode());
0085: if (!foreignKeys.containsKey(key)) {
0086: foreignKeys.put(key, computeForeignKeys(beanclass1,
0087: beanclass2));
0088: }
0089: }
0090:
0091: private String[] getForeignKeys(Class beanclass1, Class beanclass2) {
0092: Integer key = new Integer(beanclass1.hashCode()
0093: & beanclass2.hashCode());
0094: String keys[] = (String[]) foreignKeys.get(key);
0095: if (keys == null) {
0096: keys = computeForeignKeys(beanclass1, beanclass2);
0097: foreignKeys.put(key, keys);
0098: }
0099: return keys;
0100: }
0101:
0102: private String[] computeForeignKeys(Class beanclass1,
0103: Class beanclass2) {
0104: try {
0105: BeanInfo bi1 = Introspector.getBeanInfo(beanclass1);
0106: PropertyDescriptor pds1[] = bi1.getPropertyDescriptors();
0107:
0108: BeanInfo bi2 = Introspector.getBeanInfo(beanclass2);
0109: PropertyDescriptor pds2[] = bi2.getPropertyDescriptors();
0110:
0111: Vector foreign = new Vector();
0112:
0113: for (int cpt1 = 0; cpt1 < pds1.length; cpt1++) {
0114: PropertyDescriptor pd1 = pds1[cpt1];
0115: for (int cpt2 = 0; cpt2 < pds2.length; cpt2++) {
0116: PropertyDescriptor pd2 = pds2[cpt2];
0117: if ((!pd2.isHidden())
0118: && (!pd1.isHidden())
0119: && (equalsForeignKeys(pd1.getName(), pd2
0120: .getName()))) {
0121: foreign.addElement(pd1.getName());
0122: }
0123: }
0124: }
0125: String keys[] = new String[foreign.size()];
0126: foreign.copyInto(keys);
0127: return keys;
0128: } catch (IntrospectionException ex) {
0129: return new String[0];
0130: }
0131: }
0132:
0133: /**
0134: * toto_username == username
0135: */
0136: private static boolean equalsForeignKeys(String key1, String key2) {
0137: int idx1 = key1.lastIndexOf("_");
0138: if (idx1 != -1) {
0139: key1 = key1.substring(idx1);
0140: }
0141: int idx2 = key2.lastIndexOf("_");
0142: if (idx2 != -1) {
0143: key2 = key2.substring(idx2);
0144: }
0145: return key1.equals(key2);
0146: }
0147:
0148: protected void markModified(boolean modified) {
0149: this .modified = modified;
0150: }
0151:
0152: protected boolean isModified() {
0153: return modified;
0154: }
0155:
0156: /**
0157: * PropertyChangeListener implementation: This method gets called when
0158: * a bound property is changed.
0159: * @param evt A PropertyChangeEvent object describing the event source
0160: * and the property that has changed.
0161: */
0162: public void propertyChange(PropertyChangeEvent evt) {
0163: Object source = evt.getSource();
0164: String name = evt.getPropertyName();
0165: Object value = evt.getNewValue();
0166: if (source == bean) {
0167: if (value == null) {
0168: PropertyDescriptor pd = getPropertyDescriptor(name);
0169: if (JdbcBeanUtil.isJdbcBean(pd.getPropertyType())) {
0170: // delete cached bean descriptors
0171: this .beans = null;
0172: // update listeners
0173: JdbcBeanInterface oldbean = (JdbcBeanInterface) evt
0174: .getOldValue();
0175: if (oldbean != null) {
0176: PropertyCache.removeProperties(oldbean);
0177: oldbean.removePropertyChangeListener(this );
0178: }
0179: }
0180: } else if (value instanceof JdbcBeanInterface) {
0181: registerForeignKeys(bean.getClass(), value.getClass());
0182: // delete cached bean descriptors
0183: this .beans = null;
0184: // update listeners
0185: JdbcBeanInterface oldbean = (JdbcBeanInterface) evt
0186: .getOldValue();
0187: JdbcBeanInterface newbean = (JdbcBeanInterface) value;
0188: if (oldbean != null) {
0189: PropertyCache.removeProperties(oldbean);
0190: oldbean.removePropertyChangeListener(this );
0191: }
0192: newbean.addPropertyChangeListener(this );
0193: } else {
0194: JdbcBeanInterface bean = (JdbcBeanInterface) source;
0195: PropertyCache
0196: .addProperty(bean, name, evt.getNewValue());
0197: markModified(true);
0198: }
0199: } else {
0200: markModified(true);
0201: }
0202: }
0203:
0204: /**
0205: * Get the raw value of the given property, split the operator and
0206: * the value and convert the raw value into a SQL value.<p>
0207: * ie "~A.*" will become { " ~ " , "'A.*'" }
0208: * @param bean the property holder
0209: * @param pd the property descriptor
0210: */
0211: private String[] getSQLOperatorNValue(JdbcBeanInterface bean,
0212: PropertyDescriptor pd) {
0213: Class type = pd.getPropertyType();
0214: Method m = pd.getReadMethod();
0215: if (m != null) { // are we authozired to read it?
0216: // use the cache
0217: Object value = PropertyCache.getProperty(bean, pd);
0218: if (value == null) {
0219: return null;
0220: }
0221: return SQL.getSQLOperator(value);
0222: }
0223: return null;
0224: }
0225:
0226: /**
0227: * Get the SQL value of the given property.
0228: * @param bean the property holder
0229: * @param pd the property descriptor
0230: */
0231: private String getSQLValue(JdbcBeanInterface bean,
0232: PropertyDescriptor pd) {
0233: Class type = pd.getPropertyType();
0234: Method m = pd.getReadMethod();
0235: if (m != null) { // are we authozired to read it?
0236: // use the cache
0237: Object value = PropertyCache.getProperty(bean, pd);
0238: if (value == null) {
0239: return null;
0240: }
0241: return SQL.getSQLValue(value);
0242: }
0243: return null;
0244: }
0245:
0246: /**
0247: * @param name
0248: * @param value
0249: * @param buf
0250: */
0251: private void append(String name, String operator, String value,
0252: String separator, StringBuffer buf) {
0253: if (buf.length() > 0) {
0254: buf.append(separator).append(" ");
0255: }
0256: buf.append(name).append(operator).append(value).append(" ");
0257: }
0258:
0259: /**
0260: * @param name
0261: * @param value
0262: * @param namesbuffer
0263: * @param valuesbuffer
0264: */
0265: private void appendInsert(String name, String value,
0266: StringBuffer namesbuffer, StringBuffer valuesbuffer) {
0267: if (namesbuffer.length() > 0) {
0268: namesbuffer.append(", ").append(name);
0269: valuesbuffer.append(", ").append(value);
0270: } else {
0271: namesbuffer.append("(").append(name);
0272: valuesbuffer.append("(").append(value);
0273: }
0274: }
0275:
0276: private JdbcBeanInterface[] getJdbcBeans() {
0277: if (beans != null) {
0278: return beans;
0279: }
0280: try {
0281: BeanInfo info = Introspector.getBeanInfo(bean.getClass());
0282: Vector vb = new Vector();
0283: PropertyDescriptor pds[] = info.getPropertyDescriptors();
0284: for (int i = 0; i < pds.length; i++) {
0285: PropertyDescriptor pd = pds[i];
0286: if ((!pd.isHidden())
0287: && (JdbcBeanUtil.isJdbcBean(pd
0288: .getPropertyType()))) {
0289: Method m = pd.getReadMethod();
0290: if (m != null) {
0291: Object value = m.invoke(bean, (Object[]) null);
0292: if (value != null) {
0293: vb.addElement(value);
0294: }
0295: }
0296: }
0297: }
0298: beans = new JdbcBeanInterface[vb.size()];
0299: vb.copyInto(beans);
0300: return beans;
0301: } catch (IntrospectionException ex) {
0302: return null;
0303: } catch (IllegalAccessException ex) {
0304: return null;
0305: } catch (InvocationTargetException ex) {
0306: return null;
0307: }
0308: }
0309:
0310: private void appendForeignKeys(Vector tables, StringBuffer buffer,
0311: String properties[]) throws IntrospectionException {
0312: BeanInfo info = Introspector.getBeanInfo(bean.getClass());
0313: PropertyDescriptor pds[] = info.getPropertyDescriptors();
0314: appendForeignKeys(tables, buffer, pds, properties);
0315: }
0316:
0317: private void appendForeignKeys(Vector tables, StringBuffer buffer,
0318: PropertyDescriptor pds[], String properties[])
0319: throws IntrospectionException {
0320: JdbcBeanInterface jbeans[] = getJdbcBeans();
0321: if (jbeans != null) { // FOREIGN KEYs
0322: for (int i = 0; i < jbeans.length; i++) {
0323: JdbcBeanInterface jbean = jbeans[i];
0324: // foreign keys
0325: String keys[] = getForeignKeys(jbean.getClass(), bean
0326: .getClass());
0327: for (int f = 0; f < keys.length; f++) {
0328: String key = keys[f];
0329: if ((properties == null)
0330: || (JdbcBeanUtil.isIn(key, properties))) {
0331: append(jbean.getJdbcTable() + "." + key, " = ",
0332: bean.getJdbcTable() + "." + key, "AND",
0333: buffer);
0334: }
0335: }
0336: BeanInfo bi = null;
0337: PropertyDescriptor jpds[] = null;
0338: // value now
0339: bi = Introspector.getBeanInfo(jbean.getClass());
0340: jpds = bi.getPropertyDescriptors();
0341: for (int jpd_cpt = 0; jpd_cpt < jpds.length; jpd_cpt++) {
0342: PropertyDescriptor jpd = jpds[jpd_cpt];
0343: if (jpd.isHidden()) {
0344: continue;
0345: }
0346: String jname = jpd.getName();
0347: if ((properties == null)
0348: || (JdbcBeanUtil.isIn(jname, properties))) {
0349: String split[] = getSQLOperatorNValue(jbean,
0350: jpd);
0351: if (split != null) {
0352: append(jbean.getJdbcTable() + "." + jname,
0353: split[0], split[1], "AND", buffer);
0354: }
0355: }
0356: }
0357: tables.addElement(jbean);
0358: // test FIXME recursive stuff
0359: jbean.getSerializer().appendForeignKeys(tables, buffer,
0360: properties);
0361: }
0362: }
0363: }
0364:
0365: protected String computeSQLCount(boolean all, boolean distinct,
0366: String properties[]) {
0367: String count = (distinct) ? "DISTINCT count(*)" : "count(*)";
0368: return computeSQLSelect(all, count, properties);
0369: }
0370:
0371: private String computeSQLSelect(String orderby[], boolean asc[],
0372: boolean all) {
0373: return computeSQLSelect(orderby, asc, all, "*", null);
0374: }
0375:
0376: private String computeSQLSelect(String orderby[], boolean asc[],
0377: boolean all, String select) {
0378: return computeSQLSelect(orderby, asc, all, select, null);
0379: }
0380:
0381: protected String computeSQLSelect(String orderby[], boolean asc[],
0382: boolean all, String select, String properties[]) {
0383: String sql = computeSQLSelect(all, select, properties);
0384: StringBuffer buffer = new StringBuffer(sql);
0385: if (orderby != null) {
0386: buffer.append(" ORDER BY ");
0387: for (int j = 0; j < orderby.length; j++) {
0388: if (j != 0) {
0389: buffer.append(", ");
0390: }
0391: buffer.append(orderby[j]);
0392: if (!asc[j]) {
0393: buffer.append(" DESC");
0394: }
0395: }
0396: }
0397: return buffer.toString();
0398:
0399: }
0400:
0401: private String computeSQLSelect(boolean all, String select,
0402: String properties[]) {
0403: try {
0404: BeanInfo info = Introspector.getBeanInfo(bean.getClass());
0405: StringBuffer buffer = new StringBuffer();
0406: String table = bean.getJdbcTable();
0407: this .beantables = new Vector();
0408: beantables.addElement(bean);
0409:
0410: PropertyDescriptor pds[] = info.getPropertyDescriptors();
0411: if (all) {
0412: // FOREIGN KEYs
0413: appendForeignKeys(beantables, buffer, pds, properties);
0414: }
0415: // known values
0416: for (int i = 0; i < pds.length; i++) {
0417: PropertyDescriptor pd = pds[i];
0418: if (!pd.isHidden()) {
0419: String jname = pd.getName();
0420: if ((properties == null)
0421: || (JdbcBeanUtil.isIn(jname, properties))) {
0422: String split[] = getSQLOperatorNValue(bean, pd);
0423: if (split != null) {
0424: append(table + "." + jname, split[0],
0425: split[1], "AND", buffer);
0426: }
0427: }
0428: }
0429: }
0430: // build SQL request
0431: if (buffer.length() > 0) {
0432: StringBuffer tables = new StringBuffer();
0433: for (int i = 0; i < beantables.size(); i++) {
0434: JdbcBeanInterface jbean = (JdbcBeanInterface) beantables
0435: .elementAt(i);
0436: if (i != 0) {
0437: tables.append(", ");
0438: }
0439: tables.append(jbean.getJdbcTable());
0440: }
0441: tables.append(" WHERE ");
0442: tables.insert(0, "SELECT " + select + " FROM ");
0443: tables.append(buffer.toString());
0444: buffer = tables;
0445: } else {
0446: buffer = new StringBuffer("SELECT " + select + " FROM ");
0447: buffer.append(table);
0448: }
0449: // union? intersect? except?
0450: for (int i = 0; i < priority.length; i++) {
0451: int p = priority[i];
0452: if (p == NOTHING) {
0453: break;
0454: }
0455: switch (p) {
0456: case INTERSECT:
0457: if (intersect_serializer != null) {
0458: String intersect = intersect_serializer
0459: .computeSQLSelect(all, select,
0460: properties);
0461: buffer.append(" INTERSECT (").append(intersect);
0462: buffer.append(")");
0463: }
0464: break;
0465: case UNION:
0466: if (union_serializer != null) {
0467: String union = union_serializer
0468: .computeSQLSelect(all, select,
0469: properties);
0470: buffer.append(" UNION (").append(union);
0471: buffer.append(")");
0472: }
0473: break;
0474: case EXCEPT:
0475: if (except_serializer != null) {
0476: String except = except_serializer
0477: .computeSQLSelect(all, select,
0478: properties);
0479: buffer.append(" EXCEPT (").append(except);
0480: buffer.append(")");
0481: }
0482: break;
0483: default:
0484: // unreached (I hope)
0485: }
0486: }
0487: return buffer.toString();
0488: } catch (IntrospectionException ex) {
0489: return null;
0490: }
0491: }
0492:
0493: /**
0494: * Compute the SQL request necessary to update the Database.
0495: * @return a String
0496: */
0497: protected String computeSQLInsert() {
0498: try {
0499: BeanInfo info = Introspector.getBeanInfo(bean.getClass());
0500: PropertyDescriptor pds[] = info.getPropertyDescriptors();
0501: StringBuffer namesbuffer = new StringBuffer();
0502: StringBuffer valuesbuffer = new StringBuffer();
0503: for (int i = 0; i < pds.length; i++) {
0504: PropertyDescriptor pd = pds[i];
0505: if (!pd.isHidden()) {
0506: String value = getSQLValue(bean, pd);
0507: if (value != null) {
0508: appendInsert(pd.getName(), value, namesbuffer,
0509: valuesbuffer);
0510: }
0511: }
0512: }
0513: if (namesbuffer.length() > 0) {
0514: StringBuffer request = new StringBuffer("INSERT INTO ");
0515: request.append(bean.getJdbcTable()).append(" ");
0516: request.append(namesbuffer).append(") ");
0517: request.append("VALUES ").append(valuesbuffer).append(
0518: ")");
0519: return request.toString();
0520: } else {
0521: return null;
0522: }
0523: } catch (IntrospectionException ex) {
0524: return null;
0525: }
0526: }
0527:
0528: protected String computeSQLDelete() {
0529: try {
0530: BeanInfo info = Introspector.getBeanInfo(bean.getClass());
0531: StringBuffer buffer = new StringBuffer();
0532: StringBuffer table = new StringBuffer(bean.getJdbcTable());
0533: PropertyDescriptor pds[] = info.getPropertyDescriptors();
0534: // known values
0535: for (int i = 0; i < pds.length; i++) {
0536: PropertyDescriptor pd = pds[i];
0537: if (!pd.isHidden()) {
0538: String split[] = getSQLOperatorNValue(bean, pd);
0539: if (split != null) {
0540: append(pd.getName(), split[0], split[1], "AND",
0541: buffer);
0542: }
0543: }
0544: }
0545: // build SQL request
0546: if (buffer.length() > 0) {
0547: table.append(" WHERE ");
0548: table.insert(0, "DELETE FROM ");
0549: table.append(buffer.toString());
0550: buffer = table;
0551: } else {
0552: return null;
0553: }
0554: return buffer.toString();
0555: } catch (IntrospectionException ex) {
0556: return null;
0557: }
0558: }
0559:
0560: protected String computeSQLUpdate(String primarykeys[]) {
0561: try {
0562: BeanInfo info = Introspector.getBeanInfo(bean.getClass());
0563: StringBuffer buffer = new StringBuffer();
0564: StringBuffer pkbuffer = new StringBuffer();
0565: StringBuffer table = new StringBuffer(bean.getJdbcTable());
0566: PropertyDescriptor pds[] = info.getPropertyDescriptors();
0567: // known values
0568: for (int i = 0; i < pds.length; i++) {
0569: PropertyDescriptor pd = pds[i];
0570: if (!pd.isHidden()) {
0571: String name = pd.getName();
0572: String split[] = getSQLOperatorNValue(bean, pd);
0573: if (split != null) {
0574: if (JdbcBeanUtil.isIn(name, primarykeys)) {
0575: append(name, split[0], split[1], "AND",
0576: pkbuffer);
0577: } else {
0578: append(name, split[0], split[1], ",",
0579: buffer);
0580: }
0581: }
0582: }
0583: }
0584: // build SQL request
0585: if (buffer.length() > 0) {
0586: table.append(" SET ");
0587: table.insert(0, "UPDATE ");
0588: table.append(buffer.toString());
0589: table.append(" WHERE ");
0590: table.append(pkbuffer.toString());
0591: buffer = table;
0592: } else {
0593: return null;
0594: }
0595: return buffer.toString();
0596: } catch (IntrospectionException ex) {
0597: return null;
0598: }
0599: }
0600:
0601: protected JdbcServer getJdbcServer() {
0602: Properties props = new Properties();
0603: Jdbc.setMaxConn(props, bean.getMaxConn());
0604: return JdbcServer.getServer(bean.getJdbcURI(), bean
0605: .getJdbcUser(), bean.getJdbcPassword(), bean
0606: .getJdbcDriver(), props);
0607: }
0608:
0609: private void executeSQLQuery(String sqlrequest) throws SQLException {
0610: result = getJdbcServer().runQuery(sqlrequest, false);
0611: }
0612:
0613: private int executeSQLUpdate(String sqlrequest) throws SQLException {
0614: return getJdbcServer().runUpdate(sqlrequest, false);
0615: }
0616:
0617: /**
0618: * Count the number or row with columns matching the value of the
0619: * bean properties.
0620: * @return an int
0621: */
0622: public int count() {
0623: return count(true, false, null);
0624: }
0625:
0626: /**
0627: * Count the number or row with columns matching the value of the
0628: * given properties.
0629: * @param properties The property names
0630: * @return an int
0631: */
0632: public int count(String properties[]) {
0633: return count(true, false, properties);
0634: }
0635:
0636: /**
0637: * Count the number or row with columns matching the value of the
0638: * bean properties.
0639: * @param all (join with associated beans?)
0640: * @return an int
0641: */
0642: public int count(boolean all) {
0643: return count(all, false, null);
0644: }
0645:
0646: /**
0647: * Count the number or row with columns matching the value of the
0648: * bean properties
0649: * @param all (join with associated beans?)
0650: * @param distinct (SELECT DISTINCT?)
0651: * @return an int
0652: */
0653: public int count(boolean all, boolean distinct) {
0654: return count(all, distinct, null);
0655: }
0656:
0657: /**
0658: * Count the number or row with columns matching the value of the
0659: * given properties.
0660: * @param all (join with associated beans?)
0661: * @param distinct (SELECT DISTINCT?)
0662: * @param properties The property names
0663: * @return an int
0664: */
0665: public int count(boolean all, boolean distinct, String properties[]) {
0666: String sql = computeSQLCount(all, distinct, properties);
0667: try {
0668: executeSQLQuery(sql);
0669: if (result.first()) {
0670: return result.getInt(1);
0671: } else {
0672: return 0;
0673: }
0674: } catch (SQLException ex) {
0675: System.out.println("SQL STATE: " + ex.getSQLState());
0676: ex.printStackTrace();
0677: return 0;
0678: } finally {
0679: result = null;
0680: beantables = null;
0681: }
0682:
0683: }
0684:
0685: /**
0686: * Perform a sql select to update the beans properties.
0687: */
0688: public void select() {
0689: boolean array[] = { true };
0690: select((String[]) null, array, true, false);
0691: }
0692:
0693: /**
0694: * Perform a sql select to update the beans properties.
0695: * @param all join with attached beans? (default is true)
0696: */
0697: public void select(boolean all) {
0698: boolean array[] = { true };
0699: select((String[]) null, array, all, false);
0700: }
0701:
0702: /**
0703: * Perform a sql select to update the beans properties.
0704: * @param orderby orderby rule
0705: */
0706: public void select(String orderby) {
0707: String array[] = { orderby };
0708: boolean arrayb[] = { true };
0709: select(array, arrayb, true, false);
0710: }
0711:
0712: /**
0713: * Perform a sql select to update the beans properties.
0714: * @param orderby orderby rule
0715: * @param asc boolean if true orderby is ASC if false it it
0716: * DESC (relative to the orderby[] parameter)
0717: * @param all join with attached beans? (default is true)
0718: */
0719: public void select(String orderby, boolean asc, boolean all) {
0720: String array[] = { orderby };
0721: boolean arrayb[] = { asc };
0722: select(array, arrayb, all, false);
0723: }
0724:
0725: /**
0726: * Perform a sql select to update the beans properties.
0727: * @param orderby orderby rule
0728: * @param asc boolean if true orderby is ASC if false it it
0729: * DESC (relative to the orderby[] parameter)
0730: * @param all join with attached beans? (default is true)
0731: * @param distinct if true, result won't have duplicate row (default is
0732: * false)
0733: */
0734: public void select(String orderby, boolean asc, boolean all,
0735: boolean distinct) {
0736: String array[] = { orderby };
0737: boolean arrayb[] = { asc };
0738: select(array, arrayb, all, distinct);
0739: }
0740:
0741: /**
0742: * Perform a sql select to update the beans properties.
0743: * @param orderby array of orderby rules (ASC by default)
0744: */
0745: public void select(String orderby[]) {
0746: boolean array[] = { true };
0747: select(orderby, array, true, false);
0748: }
0749:
0750: /**
0751: * Perform a sql select to update the beans properties.
0752: * @param orderby array of orderby rules
0753: * @param asc array of boolean if true orderby is ASC if false it it
0754: * DESC (relative to the orderby[] parameter)
0755: * @param all join with attached beans? (default is true)
0756: * @param distinct if true, result won't have duplicate row (default is
0757: * false)
0758: */
0759: public void select(String orderby[], boolean asc[], boolean all,
0760: boolean distinct) {
0761: String select = (distinct) ? "DISTINCT *" : "*";
0762: String sql = computeSQLSelect(orderby, asc, all, select);
0763: try {
0764: executeSQLQuery(sql);
0765: } catch (SQLException ex) {
0766: System.out.println("SQL STATE: " + ex.getSQLState());
0767: ex.printStackTrace();
0768: result = null;
0769: }
0770: }
0771:
0772: /**
0773: * Perform a sql select to update the beans properties.
0774: * @param orderby array of orderby rules
0775: * @param asc array of boolean if true orderby is ASC if false it it
0776: * DESC (relative to the orderby[] parameter)
0777: * @param all join with attached beans? (default is true)
0778: * @param distinct if true, result won't have duplicate row (default is
0779: * @param toselect array of columns name to select
0780: * false)
0781: */
0782: public void select(String orderby[], boolean asc[], boolean all,
0783: boolean distinct, String toselect[]) {
0784: String query = null;
0785: if (toselect != null) {
0786: StringBuffer buffer = new StringBuffer();
0787: for (int i = 0; i < toselect.length; i++) {
0788: if (i != 0) {
0789: buffer.append(", ");
0790: }
0791: buffer.append(toselect[i]).append(" ");
0792: }
0793: query = buffer.toString();
0794: } else {
0795: query = "*";
0796: }
0797: String select = (distinct) ? "DISTINCT " + query : query;
0798: String sql = computeSQLSelect(orderby, asc, all, select);
0799: try {
0800: executeSQLQuery(sql);
0801: } catch (SQLException ex) {
0802: System.out.println("SQL STATE: " + ex.getSQLState());
0803: ex.printStackTrace();
0804: result = null;
0805: }
0806: }
0807:
0808: /**
0809: * Perform a sql select to update only the given columns. (distinct flag is
0810: * set as true.
0811: * @param column the bean property to update
0812: */
0813: public void selectDistinct(String column) {
0814: boolean array[] = { true };
0815: String order[] = { column };
0816: String sql = computeSQLSelect(order, array, false, "DISTINCT "
0817: + column);
0818: try {
0819: executeSQLQuery(sql);
0820: } catch (SQLException ex) {
0821: System.out.println("SQL STATE: " + ex.getSQLState());
0822: ex.printStackTrace();
0823: result = null;
0824: }
0825: }
0826:
0827: private void setPriority(int p) {
0828: int idx = 0;
0829: while ((idx < priority.length) && (priority[idx] != NOTHING)) {
0830: if (priority[idx] == p) { // already set
0831: return;
0832: }
0833: idx++;
0834: }
0835: priority[idx] = p;
0836: }
0837:
0838: /**
0839: * USE THIS METHOD ONLY BEFORE SELECT QUERIES.
0840: * This will produce a select query with an INTERSECT statement in it
0841: * using the values of the given bean.
0842: * @param ibean the intersect bean
0843: */
0844: public JdbcBeanSerializer intersect(JdbcBeanInterface ibean) {
0845: setPriority(INTERSECT);
0846: intersect_serializer = ibean.getSerializer();
0847: return intersect_serializer;
0848: }
0849:
0850: /**
0851: * USE THIS METHOD ONLY BEFORE QUERIES.
0852: * This will produce a select query with an UNION statement in it
0853: * using the values of the given bean.
0854: * @param ibean the intersect bean
0855: */
0856: public JdbcBeanSerializer union(JdbcBeanInterface ubean) {
0857: setPriority(UNION);
0858: union_serializer = ubean.getSerializer();
0859: return union_serializer;
0860: }
0861:
0862: /**
0863: * USE THIS METHOD ONLY BEFORE SELECT QUERIES.
0864: * This will produce a select query with an EXCEPT statement in it
0865: * using the values of the given bean.
0866: * @param ibean the intersect bean
0867: */
0868: public JdbcBeanSerializer except(JdbcBeanInterface ebean) {
0869: setPriority(EXCEPT);
0870: except_serializer = ebean.getSerializer();
0871: return except_serializer;
0872: }
0873:
0874: /**
0875: * Remove the intersect bean
0876: */
0877: public void removeIntersectBean() {
0878: intersect_serializer = null;
0879:
0880: }
0881:
0882: /**
0883: * Remove the union bean
0884: */
0885: public void removeUnionBean() {
0886: union_serializer = null;
0887:
0888: }
0889:
0890: /**
0891: * Remove the except bean
0892: */
0893: public void removeExceptBean() {
0894: except_serializer = null;
0895: }
0896:
0897: /**
0898: * Insert the current bean values in the associated table.
0899: * @return false if the INSERT request failed.
0900: */
0901: public boolean insert() {
0902: if (!isModified()) { // nothing new to insert
0903: return false;
0904: }
0905: JdbcBeanInterface beans[] = getJdbcBeans();
0906: for (int i = 0; i < beans.length; i++) {
0907: JdbcBeanInterface jbean = beans[i];
0908: JdbcBeanSerializer ser = jbean.getSerializer();
0909: if (ser.isModified()) {
0910: // insert associated bean
0911: ser.insert();
0912: // update our foreign key
0913: updateForeignKeys(jbean);
0914: }
0915: }
0916: if (!bean.getReadOnly()) {
0917: // ok insert ourself now
0918: String request = computeSQLInsert();
0919: try {
0920: // insert (could fail without being critical)
0921: // ie: when the row is already in the table
0922: executeSQLUpdate(request);
0923: } catch (SQLException ex) {
0924: System.err.println(ex.getMessage());
0925: return false;
0926: }
0927: }
0928: // update value automatically generated by the DB (index, ...)
0929: select(false);
0930: try {
0931: if (result == null) {
0932: return false;
0933: }
0934: if (result.first()) {
0935: return updateProperties(false);
0936: } else {
0937: return false;
0938: }
0939: } catch (SQLException ex) {
0940: ex.printStackTrace();
0941: return false;
0942: }
0943: }
0944:
0945: /**
0946: * Update the row relative to our bean.
0947: * @param primarykey The primary key of the SQL table
0948: * @return false if the UPDATE request failed.
0949: */
0950: public boolean update(String primarykey) {
0951: String array[] = { primarykey };
0952: return update(array);
0953: }
0954:
0955: /**
0956: * Update the row relative to our bean.
0957: * @param primarykey The primary key of the SQL table
0958: * @return false if the UPDATE request failed.
0959: */
0960: public boolean update(String primarykeys[]) {
0961: if (!isModified()) { // noting to update
0962: return false;
0963: }
0964: String sql = computeSQLUpdate(primarykeys);
0965: try {
0966: int nb = executeSQLUpdate(sql);
0967: return (nb > 0);
0968: } catch (SQLException ex) {
0969: ex.printStackTrace();
0970: }
0971: return false;
0972: }
0973:
0974: /**
0975: * Delete the row relative to the current bean.
0976: * @return false if the DELETE request failed.
0977: */
0978: public boolean delete() {
0979: if (bean.getReadOnly()) {
0980: return false;
0981: }
0982: String sql = computeSQLDelete();
0983: try {
0984: int nb = executeSQLUpdate(sql);
0985: return (nb > 0);
0986: } catch (SQLException ex) {
0987: System.out.println("SQL STATE: " + ex.getSQLState());
0988: ex.printStackTrace();
0989: result = null;
0990: return false; // FIXME VERIFY
0991: }
0992: }
0993:
0994: /**
0995: * Go to the first row
0996: * @return false if there is no first row
0997: */
0998: public boolean first() {
0999: try {
1000: if (result == null) {
1001: return false;
1002: }
1003: if (result.first()) {
1004: return updateProperties();
1005: }
1006: } catch (SQLException ex) {
1007: }
1008: return false;
1009: }
1010:
1011: /**
1012: * Update our bean with the value of the next row
1013: * @return false if there is no more row
1014: */
1015: public boolean next() {
1016: try {
1017: if (result == null) {
1018: return false;
1019: }
1020: if (result.next()) {
1021: return updateProperties();
1022: }
1023: } catch (SQLException ex) {
1024: }
1025: return false;
1026: }
1027:
1028: /**
1029: * Did we reached the last row?
1030: * @return true if the last row is reached
1031: */
1032: public boolean isLast() {
1033: try {
1034: if (result == null) {
1035: return true;
1036: }
1037: return result.isLast();
1038: } catch (SQLException ex) {
1039: }
1040: return true;
1041: }
1042:
1043: /**
1044: * Clean cached properties (relative to our bean)
1045: */
1046: public void clean() {
1047: result = null;
1048: PropertyCache.removeProperties(bean);
1049: markModified(false);
1050: }
1051:
1052: /**
1053: * Restore default value except for JdbcBean properties.
1054: */
1055: public void initBean() {
1056: try {
1057: BeanInfo info = Introspector.getBeanInfo(bean.getClass());
1058: PropertyDescriptor pds[] = info.getPropertyDescriptors();
1059: for (int i = 0; i < pds.length; i++) {
1060: PropertyDescriptor pd = pds[i];
1061: if ((!pd.isHidden())
1062: && (!JdbcBeanUtil.isJdbcBean(pd
1063: .getPropertyType()))) {
1064: Method getter = pd.getReadMethod();
1065: Method setter = pd.getWriteMethod();
1066: Object value = null;
1067: if ((getter != null) && (setter != null)) {
1068: try {
1069: value = getter.invoke(bean.getDefault(),
1070: (Object[]) null);
1071: Object array[] = { value };
1072: setter.invoke(bean, array);
1073: } catch (IllegalAccessException ex) {
1074: ex.printStackTrace();
1075: // nothing to do
1076: } catch (InvocationTargetException ex) {
1077: ex.printStackTrace();
1078: // still nothing to do
1079: } catch (IllegalArgumentException ex) {
1080: ex.printStackTrace();
1081: // nothing to do
1082: }
1083: }
1084: }
1085: }
1086: clean();
1087: } catch (IntrospectionException ex) {
1088: }
1089: }
1090:
1091: private int findColumn(Vector tables, ResultSet result,
1092: String colname) throws SQLException {
1093: String tablename = bean.getJdbcTable();
1094: ResultSetMetaData metadata = result.getMetaData();
1095: int cpt = 0;
1096: if (metadata.getTableName(1).length() > 0) { // applicable
1097: for (int i = 0; i < metadata.getColumnCount(); i++) {
1098: String coltable = metadata.getTableName(i);
1099: if ((metadata.getTableName(i)
1100: .equalsIgnoreCase(tablename))
1101: && (metadata.getColumnName(i)
1102: .equalsIgnoreCase(colname))) {
1103: return i;
1104: }
1105: }
1106: } else { // not applicable
1107: // search all columns matching the given name
1108: Vector indexes = new Vector();
1109: try {
1110: for (int i = 1; i <= metadata.getColumnCount(); i++) {
1111: if (metadata.getColumnName(i).equals(colname)) {
1112: indexes.addElement(new Integer(i));
1113: }
1114: }
1115: } catch (Exception ex) {
1116: ex.printStackTrace();
1117: }
1118: // find the good one
1119: if (indexes.size() == 0) {
1120: return -1;
1121: } else if (indexes.size() == 1) {
1122: return ((Integer) indexes.elementAt(0)).intValue();
1123: } else {
1124: int idxidx = 0;
1125: for (int i = 0; i < tables.size(); i++) {
1126: JdbcBeanInterface jbean = (JdbcBeanInterface) tables
1127: .elementAt(i);
1128: if (jbean == bean) {
1129: return ((Integer) indexes.elementAt(idxidx))
1130: .intValue();
1131: }
1132: if (jbean.getSerializer().getPropertyDescriptor(
1133: colname) != null) {
1134: // exists in this table
1135: idxidx++;
1136: }
1137: }
1138: }
1139: }
1140: return -1;
1141: }
1142:
1143: private boolean updateProperties() {
1144: return updateProperties(this .beantables, this .result, true);
1145: }
1146:
1147: private boolean updateProperties(boolean all) {
1148: return updateProperties(this .beantables, this .result, all);
1149: }
1150:
1151: private boolean updateProperties(Vector tables, ResultSet result) {
1152: return updateProperties(tables, result, true);
1153: }
1154:
1155: private boolean updateProperties(Vector tables, ResultSet result,
1156: boolean all) {
1157: try {
1158: BeanInfo info = Introspector.getBeanInfo(bean.getClass());
1159: PropertyDescriptor pds[] = info.getPropertyDescriptors();
1160: for (int i = 0; i < pds.length; i++) {
1161: PropertyDescriptor pd = pds[i];
1162: if (!pd.isHidden()) {
1163: try {
1164: int idx = findColumn(tables, result, pd
1165: .getName());
1166: if (idx != -1) {
1167: Object value = result.getObject(idx);
1168: Class propertyclass = pd.getPropertyType();
1169: value = SQL.getMatchingValue(propertyclass,
1170: value);
1171: if (value != null) {
1172: Object values[] = { value };
1173: Method setter = pd.getWriteMethod();
1174: if (setter != null) {
1175: try {
1176: setter.invoke(bean, values);
1177: } catch (IllegalAccessException ex) {
1178: ex.printStackTrace();
1179: // nothing to do
1180: } catch (InvocationTargetException ex) {
1181: ex.printStackTrace();
1182: // still nothing to do
1183: } catch (IllegalArgumentException ex) {
1184: ex.printStackTrace();
1185: // nothing to do
1186: }
1187: }
1188: } else {
1189: // default value
1190: Method getter = pd.getReadMethod();
1191: Method setter = pd.getWriteMethod();
1192: if ((getter != null)
1193: && (setter != null)) {
1194: try {
1195: value = getter.invoke(bean
1196: .getDefault(),
1197: (Object[]) null);
1198: Object array[] = { value };
1199: setter.invoke(bean, array);
1200: } catch (IllegalAccessException ex) {
1201: ex.printStackTrace();
1202: // nothing to do
1203: } catch (InvocationTargetException ex) {
1204: ex.printStackTrace();
1205: // still nothing to do
1206: } catch (IllegalArgumentException ex) {
1207: ex.printStackTrace();
1208: // nothing to do
1209: }
1210: }
1211: }
1212: }
1213: } catch (SQLException ex) { // not found
1214: // nothing to do
1215: }
1216: }
1217: }
1218: if (all) {
1219: // update the associated beans
1220: JdbcBeanInterface beans[] = getJdbcBeans();
1221: for (int i = 0; i < beans.length; i++) {
1222: beans[i].getSerializer().updateProperties(tables,
1223: result);
1224: }
1225: }
1226: markModified(false);
1227: return true;
1228: } catch (IntrospectionException ex) {
1229: return false;
1230: }
1231: }
1232:
1233: /**
1234: * Update our bean property with the given bean property
1235: * (must be an instance of the same class).
1236: * @param ubean the bean to get new properties
1237: */
1238: public void updateProperties(JdbcBeanInterface ubean) {
1239: if (ubean.getClass() != bean.getClass()) {
1240: return;
1241: }
1242: try {
1243: BeanInfo bi = Introspector.getBeanInfo(bean.getClass());
1244: PropertyDescriptor pds[] = bi.getPropertyDescriptors();
1245: for (int i = 0; i < pds.length; i++) {
1246: PropertyDescriptor pd = pds[i];
1247: if (!pd.isHidden()) {
1248: try {
1249: Method reader = pd.getReadMethod();
1250: Method writer = pd.getWriteMethod();
1251: Object value = reader.invoke(ubean,
1252: (Object[]) null);
1253: if (value != null) {
1254: Object array[] = { value };
1255: writer.invoke(bean, array);
1256: }
1257: } catch (IllegalAccessException ex) {
1258: ex.printStackTrace();
1259: } catch (InvocationTargetException ex) {
1260: ex.printStackTrace();
1261: }
1262: }
1263: }
1264: } catch (IntrospectionException ex) {
1265: // nothing to do
1266: }
1267: }
1268:
1269: private PropertyDescriptor getPropertyDescriptor(String property) {
1270: try {
1271: BeanInfo bi = Introspector.getBeanInfo(bean.getClass());
1272: PropertyDescriptor pds[] = bi.getPropertyDescriptors();
1273: for (int i = 0; i < pds.length; i++) {
1274: PropertyDescriptor pd = pds[i];
1275: if (pd.getName().equals(property)) {
1276: return pd;
1277: }
1278: }
1279: return null;
1280: } catch (IntrospectionException ex) {
1281: return null;
1282: }
1283: }
1284:
1285: private void updateForeignKeys(JdbcBeanInterface jbean) {
1286: String keys[] = getForeignKeys(jbean.getClass(), bean
1287: .getClass());
1288: JdbcBeanSerializer ser = jbean.getSerializer();
1289: for (int i = 0; i < keys.length; i++) {
1290: try {
1291: String key = keys[i];
1292: PropertyDescriptor wkeypd = getPropertyDescriptor(key);
1293: PropertyDescriptor rkeypd = ser
1294: .getPropertyDescriptor(key);
1295: Method reader = rkeypd.getReadMethod();
1296: Method writer = wkeypd.getWriteMethod();
1297: Object value = reader.invoke(jbean, (Object[]) null);
1298: if (value != null) {
1299: Object array[] = { value };
1300: writer.invoke(bean, array);
1301: }
1302: } catch (IllegalAccessException ex) {
1303: ex.printStackTrace();
1304: } catch (InvocationTargetException ex) {
1305: ex.printStackTrace();
1306: }
1307: }
1308: }
1309:
1310: /**
1311: * Called by the Garbage Collector.
1312: */
1313: protected void finalize() throws Throwable {
1314: // cleanup (static) cached properties
1315: PropertyCache.removeProperties(this .bean);
1316: }
1317:
1318: /**
1319: * Constructor
1320: * @param bean the JdbcBean to serialize
1321: */
1322: public JdbcBeanSerializer(JdbcBeanInterface bean) {
1323: this.bean = bean;
1324: bean.addPropertyChangeListener(this);
1325: }
1326:
1327: }
|