You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

QueryContainer.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. /*
  2. @VaadinApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.data.util;
  5. import java.sql.Connection;
  6. import java.sql.ResultSet;
  7. import java.sql.ResultSetMetaData;
  8. import java.sql.SQLException;
  9. import java.sql.Statement;
  10. import java.util.ArrayList;
  11. import java.util.Collection;
  12. import java.util.Collections;
  13. import java.util.HashMap;
  14. import com.vaadin.data.Container;
  15. import com.vaadin.data.Item;
  16. import com.vaadin.data.Property;
  17. /**
  18. * <p>
  19. * The <code>QueryContainer</code> is the specialized form of Container which is
  20. * Ordered and Indexed. This is used to represent the contents of relational
  21. * database tables accessed through the JDBC Connection in the Vaadin Table.
  22. * This creates Items based on the queryStatement provided to the container.
  23. * </p>
  24. *
  25. * <p>
  26. * The <code>QueryContainer</code> can be visualized as a representation of a
  27. * relational database table.Each Item in the container represents the row
  28. * fetched by the query.All cells in a column have same data type and the data
  29. * type information is retrieved from the metadata of the resultset.
  30. * </p>
  31. *
  32. * <p>
  33. * Note : If data in the tables gets modified, Container will not get reflected
  34. * with the updates, we have to explicity invoke QueryContainer.refresh method.
  35. * {@link com.vaadin.data.util.QueryContainer#refresh() refresh()}
  36. * </p>
  37. *
  38. * @see com.vaadin.data.Container
  39. *
  40. * @author Vaadin Ltd.
  41. * @version
  42. * @since 4.0
  43. *
  44. * @deprecated will be removed in the future, use the SQLContainer add-on
  45. */
  46. @Deprecated
  47. @SuppressWarnings("serial")
  48. public class QueryContainer implements Container, Container.Ordered,
  49. Container.Indexed {
  50. // default ResultSet type
  51. public static final int DEFAULT_RESULTSET_TYPE = ResultSet.TYPE_SCROLL_INSENSITIVE;
  52. // default ResultSet concurrency
  53. public static final int DEFAULT_RESULTSET_CONCURRENCY = ResultSet.CONCUR_READ_ONLY;
  54. private int resultSetType = DEFAULT_RESULTSET_TYPE;
  55. private int resultSetConcurrency = DEFAULT_RESULTSET_CONCURRENCY;
  56. private final String queryStatement;
  57. private final Connection connection;
  58. private ResultSet result;
  59. private Collection<String> propertyIds;
  60. private final HashMap<String, Class<?>> propertyTypes = new HashMap<String, Class<?>>();
  61. private int size = -1;
  62. private Statement statement;
  63. /**
  64. * Constructs new <code>QueryContainer</code> with the specified
  65. * <code>queryStatement</code>.
  66. *
  67. * @param queryStatement
  68. * Database query
  69. * @param connection
  70. * Connection object
  71. * @param resultSetType
  72. * @param resultSetConcurrency
  73. * @throws SQLException
  74. * when database operation fails
  75. */
  76. public QueryContainer(String queryStatement, Connection connection,
  77. int resultSetType, int resultSetConcurrency) throws SQLException {
  78. this.queryStatement = queryStatement;
  79. this.connection = connection;
  80. this.resultSetType = resultSetType;
  81. this.resultSetConcurrency = resultSetConcurrency;
  82. init();
  83. }
  84. /**
  85. * Constructs new <code>QueryContainer</code> with the specified
  86. * queryStatement using the default resultset type and default resultset
  87. * concurrency.
  88. *
  89. * @param queryStatement
  90. * Database query
  91. * @param connection
  92. * Connection object
  93. * @see QueryContainer#DEFAULT_RESULTSET_TYPE
  94. * @see QueryContainer#DEFAULT_RESULTSET_CONCURRENCY
  95. * @throws SQLException
  96. * when database operation fails
  97. */
  98. public QueryContainer(String queryStatement, Connection connection)
  99. throws SQLException {
  100. this(queryStatement, connection, DEFAULT_RESULTSET_TYPE,
  101. DEFAULT_RESULTSET_CONCURRENCY);
  102. }
  103. /**
  104. * Fills the Container with the items and properties. Invoked by the
  105. * constructor.
  106. *
  107. * @throws SQLException
  108. * when parameter initialization fails.
  109. * @see QueryContainer#QueryContainer(String, Connection, int, int).
  110. */
  111. private void init() throws SQLException {
  112. refresh();
  113. ResultSetMetaData metadata;
  114. metadata = result.getMetaData();
  115. final int count = metadata.getColumnCount();
  116. final ArrayList<String> list = new ArrayList<String>(count);
  117. for (int i = 1; i <= count; i++) {
  118. final String columnName = metadata.getColumnName(i);
  119. list.add(columnName);
  120. final Property<?> p = getContainerProperty(new Integer(1),
  121. columnName);
  122. propertyTypes.put(columnName,
  123. p == null ? Object.class : p.getType());
  124. }
  125. propertyIds = Collections.unmodifiableCollection(list);
  126. }
  127. /**
  128. * <p>
  129. * Restores items in the container. This method will update the latest data
  130. * to the container.
  131. * </p>
  132. * Note: This method should be used to update the container with the latest
  133. * items.
  134. *
  135. * @throws SQLException
  136. * when database operation fails
  137. *
  138. */
  139. public void refresh() throws SQLException {
  140. close();
  141. statement = connection.createStatement(resultSetType,
  142. resultSetConcurrency);
  143. result = statement.executeQuery(queryStatement);
  144. result.last();
  145. size = result.getRow();
  146. }
  147. /**
  148. * Releases and nullifies the <code>statement</code>.
  149. *
  150. * @throws SQLException
  151. * when database operation fails
  152. */
  153. public void close() throws SQLException {
  154. if (statement != null) {
  155. statement.close();
  156. }
  157. statement = null;
  158. }
  159. /**
  160. * Gets the Item with the given Item ID from the Container.
  161. *
  162. * @param id
  163. * ID of the Item to retrieve
  164. * @return Item Id.
  165. */
  166. @Override
  167. public Item getItem(Object id) {
  168. return new Row(id);
  169. }
  170. /**
  171. * Gets the collection of propertyId from the Container.
  172. *
  173. * @return Collection of Property ID.
  174. */
  175. @Override
  176. public Collection<String> getContainerPropertyIds() {
  177. return propertyIds;
  178. }
  179. /**
  180. * Gets an collection of all the item IDs in the container.
  181. *
  182. * @return collection of Item IDs
  183. */
  184. @Override
  185. public Collection<?> getItemIds() {
  186. final Collection<Integer> c = new ArrayList<Integer>(size);
  187. for (int i = 1; i <= size; i++) {
  188. c.add(new Integer(i));
  189. }
  190. return c;
  191. }
  192. /**
  193. * Gets the property identified by the given itemId and propertyId from the
  194. * container. If the container does not contain the property
  195. * <code>null</code> is returned.
  196. *
  197. * @param itemId
  198. * ID of the Item which contains the Property
  199. * @param propertyId
  200. * ID of the Property to retrieve
  201. *
  202. * @return Property with the given ID if exists; <code>null</code>
  203. * otherwise.
  204. */
  205. @Override
  206. public synchronized Property<?> getContainerProperty(Object itemId,
  207. Object propertyId) {
  208. if (!(itemId instanceof Integer && propertyId instanceof String)) {
  209. return null;
  210. }
  211. Object value;
  212. try {
  213. result.absolute(((Integer) itemId).intValue());
  214. value = result.getObject((String) propertyId);
  215. } catch (final Exception e) {
  216. return null;
  217. }
  218. // Handle also null values from the database
  219. return new ObjectProperty<Object>(value != null ? value
  220. : new String(""));
  221. }
  222. /**
  223. * Gets the data type of all properties identified by the given type ID.
  224. *
  225. * @param id
  226. * ID identifying the Properties
  227. *
  228. * @return data type of the Properties
  229. */
  230. @Override
  231. public Class<?> getType(Object id) {
  232. return propertyTypes.get(id);
  233. }
  234. /**
  235. * Gets the number of items in the container.
  236. *
  237. * @return the number of items in the container.
  238. */
  239. @Override
  240. public int size() {
  241. return size;
  242. }
  243. /**
  244. * Tests if the list contains the specified Item.
  245. *
  246. * @param id
  247. * ID the of Item to be tested.
  248. * @return <code>true</code> if given id is in the container;
  249. * <code>false</code> otherwise.
  250. */
  251. @Override
  252. public boolean containsId(Object id) {
  253. if (!(id instanceof Integer)) {
  254. return false;
  255. }
  256. final int i = ((Integer) id).intValue();
  257. if (i < 1) {
  258. return false;
  259. }
  260. if (i > size) {
  261. return false;
  262. }
  263. return true;
  264. }
  265. /**
  266. * Creates new Item with the given ID into the Container.
  267. *
  268. * @param itemId
  269. * ID of the Item to be created.
  270. *
  271. * @return Created new Item, or <code>null</code> if it fails.
  272. *
  273. * @throws UnsupportedOperationException
  274. * if the addItem method is not supported.
  275. */
  276. @Override
  277. public Item addItem(Object itemId) throws UnsupportedOperationException {
  278. throw new UnsupportedOperationException();
  279. }
  280. /**
  281. * Creates a new Item into the Container, and assign it an ID.
  282. *
  283. * @return ID of the newly created Item, or <code>null</code> if it fails.
  284. * @throws UnsupportedOperationException
  285. * if the addItem method is not supported.
  286. */
  287. @Override
  288. public Object addItem() throws UnsupportedOperationException {
  289. throw new UnsupportedOperationException();
  290. }
  291. /**
  292. * Removes the Item identified by ItemId from the Container.
  293. *
  294. * @param itemId
  295. * ID of the Item to remove.
  296. * @return <code>true</code> if the operation succeeded; <code>false</code>
  297. * otherwise.
  298. * @throws UnsupportedOperationException
  299. * if the removeItem method is not supported.
  300. */
  301. @Override
  302. public boolean removeItem(Object itemId)
  303. throws UnsupportedOperationException {
  304. throw new UnsupportedOperationException();
  305. }
  306. /**
  307. * Adds new Property to all Items in the Container.
  308. *
  309. * @param propertyId
  310. * ID of the Property
  311. * @param type
  312. * Data type of the new Property
  313. * @param defaultValue
  314. * The value all created Properties are initialized to.
  315. * @return <code>true</code> if the operation succeeded; <code>false</code>
  316. * otherwise.
  317. * @throws UnsupportedOperationException
  318. * if the addContainerProperty method is not supported.
  319. */
  320. @Override
  321. public boolean addContainerProperty(Object propertyId, Class<?> type,
  322. Object defaultValue) throws UnsupportedOperationException {
  323. throw new UnsupportedOperationException();
  324. }
  325. /**
  326. * Removes a Property specified by the given Property ID from the Container.
  327. *
  328. * @param propertyId
  329. * ID of the Property to remove
  330. * @return <code>true</code> if the operation succeeded; <code>false</code>
  331. * otherwise.
  332. * @throws UnsupportedOperationException
  333. * if the removeContainerProperty method is not supported.
  334. */
  335. @Override
  336. public boolean removeContainerProperty(Object propertyId)
  337. throws UnsupportedOperationException {
  338. throw new UnsupportedOperationException();
  339. }
  340. /**
  341. * Removes all Items from the Container.
  342. *
  343. * @return <code>true</code> if the operation succeeded; <code>false</code>
  344. * otherwise.
  345. * @throws UnsupportedOperationException
  346. * if the removeAllItems method is not supported.
  347. */
  348. @Override
  349. public boolean removeAllItems() throws UnsupportedOperationException {
  350. throw new UnsupportedOperationException();
  351. }
  352. /**
  353. * Adds new item after the given item.
  354. *
  355. * @param previousItemId
  356. * Id of the previous item in ordered container.
  357. * @param newItemId
  358. * Id of the new item to be added.
  359. * @return Returns new item or <code>null</code> if the operation fails.
  360. * @throws UnsupportedOperationException
  361. * if the addItemAfter method is not supported.
  362. */
  363. @Override
  364. public Item addItemAfter(Object previousItemId, Object newItemId)
  365. throws UnsupportedOperationException {
  366. throw new UnsupportedOperationException();
  367. }
  368. /**
  369. * Adds new item after the given item.
  370. *
  371. * @param previousItemId
  372. * Id of the previous item in ordered container.
  373. * @return Returns item id created new item or <code>null</code> if the
  374. * operation fails.
  375. * @throws UnsupportedOperationException
  376. * if the addItemAfter method is not supported.
  377. */
  378. @Override
  379. public Object addItemAfter(Object previousItemId)
  380. throws UnsupportedOperationException {
  381. throw new UnsupportedOperationException();
  382. }
  383. /**
  384. * Returns id of first item in the Container.
  385. *
  386. * @return ID of the first Item in the list.
  387. */
  388. @Override
  389. public Object firstItemId() {
  390. if (size < 1) {
  391. return null;
  392. }
  393. return new Integer(1);
  394. }
  395. /**
  396. * Returns <code>true</code> if given id is first id at first index.
  397. *
  398. * @param id
  399. * ID of an Item in the Container.
  400. */
  401. @Override
  402. public boolean isFirstId(Object id) {
  403. return size > 0 && (id instanceof Integer)
  404. && ((Integer) id).intValue() == 1;
  405. }
  406. /**
  407. * Returns <code>true</code> if given id is last id at last index.
  408. *
  409. * @param id
  410. * ID of an Item in the Container
  411. *
  412. */
  413. @Override
  414. public boolean isLastId(Object id) {
  415. return size > 0 && (id instanceof Integer)
  416. && ((Integer) id).intValue() == size;
  417. }
  418. /**
  419. * Returns id of last item in the Container.
  420. *
  421. * @return ID of the last Item.
  422. */
  423. @Override
  424. public Object lastItemId() {
  425. if (size < 1) {
  426. return null;
  427. }
  428. return new Integer(size);
  429. }
  430. /**
  431. * Returns id of next item in container at next index.
  432. *
  433. * @param id
  434. * ID of an Item in the Container.
  435. * @return ID of the next Item or null.
  436. */
  437. @Override
  438. public Object nextItemId(Object id) {
  439. if (size < 1 || !(id instanceof Integer)) {
  440. return null;
  441. }
  442. final int i = ((Integer) id).intValue();
  443. if (i >= size) {
  444. return null;
  445. }
  446. return new Integer(i + 1);
  447. }
  448. /**
  449. * Returns id of previous item in container at previous index.
  450. *
  451. * @param id
  452. * ID of an Item in the Container.
  453. * @return ID of the previous Item or null.
  454. */
  455. @Override
  456. public Object prevItemId(Object id) {
  457. if (size < 1 || !(id instanceof Integer)) {
  458. return null;
  459. }
  460. final int i = ((Integer) id).intValue();
  461. if (i <= 1) {
  462. return null;
  463. }
  464. return new Integer(i - 1);
  465. }
  466. /**
  467. * The <code>Row</code> class implements methods of Item.
  468. *
  469. * @author Vaadin Ltd.
  470. * @version
  471. * @since 4.0
  472. */
  473. class Row implements Item {
  474. Object id;
  475. private Row(Object rowId) {
  476. id = rowId;
  477. }
  478. /**
  479. * Adds the item property.
  480. *
  481. * @param id
  482. * ID of the new Property.
  483. * @param property
  484. * Property to be added and associated with ID.
  485. * @return <code>true</code> if the operation succeeded;
  486. * <code>false</code> otherwise.
  487. * @throws UnsupportedOperationException
  488. * if the addItemProperty method is not supported.
  489. */
  490. @Override
  491. public boolean addItemProperty(Object id, Property property)
  492. throws UnsupportedOperationException {
  493. throw new UnsupportedOperationException();
  494. }
  495. /**
  496. * Gets the property corresponding to the given property ID stored in
  497. * the Item.
  498. *
  499. * @param propertyId
  500. * identifier of the Property to get
  501. * @return the Property with the given ID or <code>null</code>
  502. */
  503. @Override
  504. public Property<?> getItemProperty(Object propertyId) {
  505. return getContainerProperty(id, propertyId);
  506. }
  507. /**
  508. * Gets the collection of property IDs stored in the Item.
  509. *
  510. * @return unmodifiable collection containing IDs of the Properties
  511. * stored the Item.
  512. */
  513. @Override
  514. public Collection<String> getItemPropertyIds() {
  515. return propertyIds;
  516. }
  517. /**
  518. * Removes given item property.
  519. *
  520. * @param id
  521. * ID of the Property to be removed.
  522. * @return <code>true</code> if the item property is removed;
  523. * <code>false</code> otherwise.
  524. * @throws UnsupportedOperationException
  525. * if the removeItemProperty is not supported.
  526. */
  527. @Override
  528. public boolean removeItemProperty(Object id)
  529. throws UnsupportedOperationException {
  530. throw new UnsupportedOperationException();
  531. }
  532. }
  533. /**
  534. * Closes the statement.
  535. *
  536. * @see #close()
  537. */
  538. @Override
  539. public void finalize() {
  540. try {
  541. close();
  542. } catch (final SQLException ignored) {
  543. }
  544. }
  545. /**
  546. * Adds the given item at the position of given index.
  547. *
  548. * @param index
  549. * Index to add the new item.
  550. * @param newItemId
  551. * Id of the new item to be added.
  552. * @return new item or <code>null</code> if the operation fails.
  553. * @throws UnsupportedOperationException
  554. * if the addItemAt is not supported.
  555. */
  556. @Override
  557. public Item addItemAt(int index, Object newItemId)
  558. throws UnsupportedOperationException {
  559. throw new UnsupportedOperationException();
  560. }
  561. /**
  562. * Adds item at the position of provided index in the container.
  563. *
  564. * @param index
  565. * Index to add the new item.
  566. * @return item id created new item or <code>null</code> if the operation
  567. * fails.
  568. *
  569. * @throws UnsupportedOperationException
  570. * if the addItemAt is not supported.
  571. */
  572. @Override
  573. public Object addItemAt(int index) throws UnsupportedOperationException {
  574. throw new UnsupportedOperationException();
  575. }
  576. /**
  577. * Gets the Index id in the container.
  578. *
  579. * @param index
  580. * Index Id.
  581. * @return ID in the given index.
  582. */
  583. @Override
  584. public Object getIdByIndex(int index) {
  585. if (size < 1 || index < 0 || index >= size) {
  586. return null;
  587. }
  588. return new Integer(index + 1);
  589. }
  590. /**
  591. * Gets the index of the Item corresponding to id in the container.
  592. *
  593. * @param id
  594. * ID of an Item in the Container
  595. * @return index of the Item, or -1 if the Container does not include the
  596. * Item
  597. */
  598. @Override
  599. public int indexOfId(Object id) {
  600. if (size < 1 || !(id instanceof Integer)) {
  601. return -1;
  602. }
  603. final int i = ((Integer) id).intValue();
  604. if (i >= size || i < 1) {
  605. return -1;
  606. }
  607. return i - 1;
  608. }
  609. }