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 20KB

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