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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  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), columnName);
  121. propertyTypes.put(columnName,
  122. p == null ? Object.class : p.getType());
  123. }
  124. propertyIds = Collections.unmodifiableCollection(list);
  125. }
  126. /**
  127. * <p>
  128. * Restores items in the container. This method will update the latest data
  129. * to the container.
  130. * </p>
  131. * Note: This method should be used to update the container with the latest
  132. * items.
  133. *
  134. * @throws SQLException
  135. * when database operation fails
  136. *
  137. */
  138. public void refresh() throws SQLException {
  139. close();
  140. statement = connection.createStatement(resultSetType,
  141. resultSetConcurrency);
  142. result = statement.executeQuery(queryStatement);
  143. result.last();
  144. size = result.getRow();
  145. }
  146. /**
  147. * Releases and nullifies the <code>statement</code>.
  148. *
  149. * @throws SQLException
  150. * when database operation fails
  151. */
  152. public void close() throws SQLException {
  153. if (statement != null) {
  154. statement.close();
  155. }
  156. statement = null;
  157. }
  158. /**
  159. * Gets the Item with the given Item ID from the Container.
  160. *
  161. * @param id
  162. * ID of the Item to retrieve
  163. * @return Item Id.
  164. */
  165. public Item getItem(Object id) {
  166. return new Row(id);
  167. }
  168. /**
  169. * Gets the collection of propertyId from the Container.
  170. *
  171. * @return Collection of Property ID.
  172. */
  173. public Collection<String> getContainerPropertyIds() {
  174. return propertyIds;
  175. }
  176. /**
  177. * Gets an collection of all the item IDs in the container.
  178. *
  179. * @return collection of Item IDs
  180. */
  181. public Collection<?> getItemIds() {
  182. final Collection<Integer> c = new ArrayList<Integer>(size);
  183. for (int i = 1; i <= size; i++) {
  184. c.add(new Integer(i));
  185. }
  186. return c;
  187. }
  188. /**
  189. * Gets the property identified by the given itemId and propertyId from the
  190. * container. If the container does not contain the property
  191. * <code>null</code> is returned.
  192. *
  193. * @param itemId
  194. * ID of the Item which contains the Property
  195. * @param propertyId
  196. * ID of the Property to retrieve
  197. *
  198. * @return Property with the given ID if exists; <code>null</code>
  199. * otherwise.
  200. */
  201. public synchronized Property getContainerProperty(Object itemId,
  202. Object propertyId) {
  203. if (!(itemId instanceof Integer && propertyId instanceof String)) {
  204. return null;
  205. }
  206. Object value;
  207. try {
  208. result.absolute(((Integer) itemId).intValue());
  209. value = result.getObject((String) propertyId);
  210. } catch (final Exception e) {
  211. return null;
  212. }
  213. // Handle also null values from the database
  214. return new ObjectProperty<Object>(value != null ? value
  215. : new String(""));
  216. }
  217. /**
  218. * Gets the data type of all properties identified by the given type ID.
  219. *
  220. * @param id
  221. * ID identifying the Properties
  222. *
  223. * @return data type of the Properties
  224. */
  225. public Class<?> getType(Object id) {
  226. return propertyTypes.get(id);
  227. }
  228. /**
  229. * Gets the number of items in the container.
  230. *
  231. * @return the number of items in the container.
  232. */
  233. public int size() {
  234. return size;
  235. }
  236. /**
  237. * Tests if the list contains the specified Item.
  238. *
  239. * @param id
  240. * ID the of Item to be tested.
  241. * @return <code>true</code> if given id is in the container;
  242. * <code>false</code> otherwise.
  243. */
  244. public boolean containsId(Object id) {
  245. if (!(id instanceof Integer)) {
  246. return false;
  247. }
  248. final int i = ((Integer) id).intValue();
  249. if (i < 1) {
  250. return false;
  251. }
  252. if (i > size) {
  253. return false;
  254. }
  255. return true;
  256. }
  257. /**
  258. * Creates new Item with the given ID into the Container.
  259. *
  260. * @param itemId
  261. * ID of the Item to be created.
  262. *
  263. * @return Created new Item, or <code>null</code> if it fails.
  264. *
  265. * @throws UnsupportedOperationException
  266. * if the addItem method is not supported.
  267. */
  268. public Item addItem(Object itemId) throws UnsupportedOperationException {
  269. throw new UnsupportedOperationException();
  270. }
  271. /**
  272. * Creates a new Item into the Container, and assign it an ID.
  273. *
  274. * @return ID of the newly created Item, or <code>null</code> if it fails.
  275. * @throws UnsupportedOperationException
  276. * if the addItem method is not supported.
  277. */
  278. public Object addItem() throws UnsupportedOperationException {
  279. throw new UnsupportedOperationException();
  280. }
  281. /**
  282. * Removes the Item identified by ItemId from the Container.
  283. *
  284. * @param itemId
  285. * ID of the Item to remove.
  286. * @return <code>true</code> if the operation succeeded; <code>false</code>
  287. * otherwise.
  288. * @throws UnsupportedOperationException
  289. * if the removeItem method is not supported.
  290. */
  291. public boolean removeItem(Object itemId)
  292. throws UnsupportedOperationException {
  293. throw new UnsupportedOperationException();
  294. }
  295. /**
  296. * Adds new Property to all Items in the Container.
  297. *
  298. * @param propertyId
  299. * ID of the Property
  300. * @param type
  301. * Data type of the new Property
  302. * @param defaultValue
  303. * The value all created Properties are initialized to.
  304. * @return <code>true</code> if the operation succeeded; <code>false</code>
  305. * otherwise.
  306. * @throws UnsupportedOperationException
  307. * if the addContainerProperty method is not supported.
  308. */
  309. public boolean addContainerProperty(Object propertyId, Class<?> type,
  310. Object defaultValue) throws UnsupportedOperationException {
  311. throw new UnsupportedOperationException();
  312. }
  313. /**
  314. * Removes a Property specified by the given Property ID from the Container.
  315. *
  316. * @param propertyId
  317. * ID of the Property to remove
  318. * @return <code>true</code> if the operation succeeded; <code>false</code>
  319. * otherwise.
  320. * @throws UnsupportedOperationException
  321. * if the removeContainerProperty method is not supported.
  322. */
  323. public boolean removeContainerProperty(Object propertyId)
  324. throws UnsupportedOperationException {
  325. throw new UnsupportedOperationException();
  326. }
  327. /**
  328. * Removes all Items from the Container.
  329. *
  330. * @return <code>true</code> if the operation succeeded; <code>false</code>
  331. * otherwise.
  332. * @throws UnsupportedOperationException
  333. * if the removeAllItems method is not supported.
  334. */
  335. public boolean removeAllItems() throws UnsupportedOperationException {
  336. throw new UnsupportedOperationException();
  337. }
  338. /**
  339. * Adds new item after the given item.
  340. *
  341. * @param previousItemId
  342. * Id of the previous item in ordered container.
  343. * @param newItemId
  344. * Id of the new item to be added.
  345. * @return Returns new item or <code>null</code> if the operation fails.
  346. * @throws UnsupportedOperationException
  347. * if the addItemAfter method is not supported.
  348. */
  349. public Item addItemAfter(Object previousItemId, Object newItemId)
  350. throws UnsupportedOperationException {
  351. throw new UnsupportedOperationException();
  352. }
  353. /**
  354. * Adds new item after the given item.
  355. *
  356. * @param previousItemId
  357. * Id of the previous item in ordered container.
  358. * @return Returns item id created new item or <code>null</code> if the
  359. * operation fails.
  360. * @throws UnsupportedOperationException
  361. * if the addItemAfter method is not supported.
  362. */
  363. public Object addItemAfter(Object previousItemId)
  364. throws UnsupportedOperationException {
  365. throw new UnsupportedOperationException();
  366. }
  367. /**
  368. * Returns id of first item in the Container.
  369. *
  370. * @return ID of the first Item in the list.
  371. */
  372. public Object firstItemId() {
  373. if (size < 1) {
  374. return null;
  375. }
  376. return new Integer(1);
  377. }
  378. /**
  379. * Returns <code>true</code> if given id is first id at first index.
  380. *
  381. * @param id
  382. * ID of an Item in the Container.
  383. */
  384. public boolean isFirstId(Object id) {
  385. return size > 0 && (id instanceof Integer)
  386. && ((Integer) id).intValue() == 1;
  387. }
  388. /**
  389. * Returns <code>true</code> if given id is last id at last index.
  390. *
  391. * @param id
  392. * ID of an Item in the Container
  393. *
  394. */
  395. public boolean isLastId(Object id) {
  396. return size > 0 && (id instanceof Integer)
  397. && ((Integer) id).intValue() == size;
  398. }
  399. /**
  400. * Returns id of last item in the Container.
  401. *
  402. * @return ID of the last Item.
  403. */
  404. public Object lastItemId() {
  405. if (size < 1) {
  406. return null;
  407. }
  408. return new Integer(size);
  409. }
  410. /**
  411. * Returns id of next item in container at next index.
  412. *
  413. * @param id
  414. * ID of an Item in the Container.
  415. * @return ID of the next Item or null.
  416. */
  417. public Object nextItemId(Object id) {
  418. if (size < 1 || !(id instanceof Integer)) {
  419. return null;
  420. }
  421. final int i = ((Integer) id).intValue();
  422. if (i >= size) {
  423. return null;
  424. }
  425. return new Integer(i + 1);
  426. }
  427. /**
  428. * Returns id of previous item in container at previous index.
  429. *
  430. * @param id
  431. * ID of an Item in the Container.
  432. * @return ID of the previous Item or null.
  433. */
  434. public Object prevItemId(Object id) {
  435. if (size < 1 || !(id instanceof Integer)) {
  436. return null;
  437. }
  438. final int i = ((Integer) id).intValue();
  439. if (i <= 1) {
  440. return null;
  441. }
  442. return new Integer(i - 1);
  443. }
  444. /**
  445. * The <code>Row</code> class implements methods of Item.
  446. *
  447. * @author Vaadin Ltd.
  448. * @version
  449. * @since 4.0
  450. */
  451. class Row implements Item {
  452. Object id;
  453. private Row(Object rowId) {
  454. id = rowId;
  455. }
  456. /**
  457. * Adds the item property.
  458. *
  459. * @param id
  460. * ID of the new Property.
  461. * @param property
  462. * Property to be added and associated with ID.
  463. * @return <code>true</code> if the operation succeeded;
  464. * <code>false</code> otherwise.
  465. * @throws UnsupportedOperationException
  466. * if the addItemProperty method is not supported.
  467. */
  468. public boolean addItemProperty(Object id, Property property)
  469. throws UnsupportedOperationException {
  470. throw new UnsupportedOperationException();
  471. }
  472. /**
  473. * Gets the property corresponding to the given property ID stored in
  474. * the Item.
  475. *
  476. * @param propertyId
  477. * identifier of the Property to get
  478. * @return the Property with the given ID or <code>null</code>
  479. */
  480. public Property getItemProperty(Object propertyId) {
  481. return getContainerProperty(id, propertyId);
  482. }
  483. /**
  484. * Gets the collection of property IDs stored in the Item.
  485. *
  486. * @return unmodifiable collection containing IDs of the Properties
  487. * stored the Item.
  488. */
  489. public Collection<String> getItemPropertyIds() {
  490. return propertyIds;
  491. }
  492. /**
  493. * Removes given item property.
  494. *
  495. * @param id
  496. * ID of the Property to be removed.
  497. * @return <code>true</code> if the item property is removed;
  498. * <code>false</code> otherwise.
  499. * @throws UnsupportedOperationException
  500. * if the removeItemProperty is not supported.
  501. */
  502. public boolean removeItemProperty(Object id)
  503. throws UnsupportedOperationException {
  504. throw new UnsupportedOperationException();
  505. }
  506. }
  507. /**
  508. * Closes the statement.
  509. *
  510. * @see #close()
  511. */
  512. @Override
  513. public void finalize() {
  514. try {
  515. close();
  516. } catch (final SQLException ignored) {
  517. }
  518. }
  519. /**
  520. * Adds the given item at the position of given index.
  521. *
  522. * @param index
  523. * Index to add the new item.
  524. * @param newItemId
  525. * Id of the new item to be added.
  526. * @return new item or <code>null</code> if the operation fails.
  527. * @throws UnsupportedOperationException
  528. * if the addItemAt is not supported.
  529. */
  530. public Item addItemAt(int index, Object newItemId)
  531. throws UnsupportedOperationException {
  532. throw new UnsupportedOperationException();
  533. }
  534. /**
  535. * Adds item at the position of provided index in the container.
  536. *
  537. * @param index
  538. * Index to add the new item.
  539. * @return item id created new item or <code>null</code> if the operation
  540. * fails.
  541. *
  542. * @throws UnsupportedOperationException
  543. * if the addItemAt is not supported.
  544. */
  545. public Object addItemAt(int index) throws UnsupportedOperationException {
  546. throw new UnsupportedOperationException();
  547. }
  548. /**
  549. * Gets the Index id in the container.
  550. *
  551. * @param index
  552. * Index Id.
  553. * @return ID in the given index.
  554. */
  555. public Object getIdByIndex(int index) {
  556. if (size < 1 || index < 0 || index >= size) {
  557. return null;
  558. }
  559. return new Integer(index + 1);
  560. }
  561. /**
  562. * Gets the index of the Item corresponding to id in the container.
  563. *
  564. * @param id
  565. * ID of an Item in the Container
  566. * @return index of the Item, or -1 if the Container does not include the
  567. * Item
  568. */
  569. public int indexOfId(Object id) {
  570. if (size < 1 || !(id instanceof Integer)) {
  571. return -1;
  572. }
  573. final int i = ((Integer) id).intValue();
  574. if (i >= size || i < 1) {
  575. return -1;
  576. }
  577. return i - 1;
  578. }
  579. }