1 /* 2 * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /** 27 * The standard classes and interfaces that a third party vendor has to 28 * use in its implementation of a synchronization provider. These classes and 29 * interfaces are referred to as the Service Provider Interface (SPI). To make it possible 30 * for a <code>RowSet</code> object to use an implementation, the vendor must register 31 * it with the <code>SyncFactory</code> singleton. (See the class comment for 32 * <code>SyncProvider</code> for a full explanation of the registration process and 33 * the naming convention to be used.) 34 * 35 * <h2>Table of Contents</h2> 36 * <ul> 37 * <li><a href="#pkgspec">1.0 Package Specification</a> 38 * <li><a href="#arch">2.0 Service Provider Architecture</a> 39 * <li><a href="#impl">3.0 Implementer's Guide</a> 40 * <li><a href="#resolving">4.0 Resolving Synchronization Conflicts</a> 41 * <li><a href="#relspec">5.0 Related Specifications</a> 42 * <li><a href="#reldocs">6.0 Related Documentation</a> 43 * </ul> 44 * 45 * <h3><a id="pkgspec">1.0 Package Specification</a></h3> 46 * <P> 47 * The following classes and interfaces make up the <code>javax.sql.rowset.spi</code> 48 * package: 49 * <UL> 50 * <LI><code>SyncFactory</code> 51 * <LI><code>SyncProvider</code> 52 * <LI><code>SyncFactoryException</code> 53 * <LI><code>SyncProviderException</code> 54 * <LI><code>SyncResolver</code> 55 * <LI><code>XmlReader</code> 56 * <LI><code>XmlWriter</code> 57 * <LI><code>TransactionalWriter</code> 58 * </UL> 59 * The following interfaces, in the <code>javax.sql</code> package, are also part of the SPI: 60 * <UL> 61 * <LI><code>RowSetReader</code> 62 * <LI><code>RowSetWriter</code> 63 * </UL> 64 * <P> 65 * A <code>SyncProvider</code> implementation provides a disconnected <code>RowSet</code> 66 * object with the mechanisms for reading data into it and for writing data that has been 67 * modified in it 68 * back to the underlying data source. A <i>reader</i>, a <code>RowSetReader</code> or 69 * <code>XMLReader</code> object, reads data into a <code>RowSet</code> object when the 70 * <code>CachedRowSet</code> methods <code>execute</code> or <code>populate</code> 71 * are called. A <i>writer</i>, a <code>RowSetWriter</code> or <code>XMLWriter</code> 72 * object, writes changes back to the underlying data source when the 73 * <code>CachedRowSet</code> method <code>acceptChanges</code> is called. 74 * <P> 75 * The process of writing changes in a <code>RowSet</code> object to its data source 76 * is known as <i>synchronization</i>. The <code>SyncProvider</code> implementation that a 77 * <code>RowSet</code> object is using determines the level of synchronization that the 78 * <code>RowSet</code> object's writer uses. The various levels of synchronization are 79 * referred to as <i>grades</i>. 80 * <P> 81 * The lower grades of synchronization are 82 * known as <i>optimistic</i> concurrency levels because they optimistically 83 * assume that there will be no conflicts or very few conflicts. A conflict exists when 84 * the same data modified in the <code>RowSet</code> object has also been modified 85 * in the data source. Using the optimistic concurrency model means that if there 86 * is a conflict, modifications to either the data source or the <code>RowSet</code> 87 * object will be lost. 88 * <P> 89 * Higher grades of synchronization are called <i>pessimistic</i> because they assume 90 * that others will be accessing the data source and making modifications. These 91 * grades set varying levels of locks to increase the chances that no conflicts 92 * occur. 93 * <P> 94 * The lowest level of synchronization is simply writing any changes made to the 95 * <code>RowSet</code> object to its underlying data source. The writer does 96 * nothing to check for conflicts. 97 * If there is a conflict and the data 98 * source values are overwritten, the changes other parties have made by to the data 99 * source are lost. 100 * <P> 101 * The <code>RIXMLProvider</code> implementation uses the lowest level 102 * of synchronization and just writes <code>RowSet</code> changes to the data source. 103 * 104 * <P> 105 * For the next level up, the 106 * writer checks to see if there are any conflicts, and if there are, 107 * it does not write anything to the data source. The problem with this concurrency 108 * level is that if another party has modified the corresponding data in the data source 109 * since the <code>RowSet</code> object got its data, 110 * the changes made to the <code>RowSet</code> object are lost. The 111 * <code>RIOptimisticProvider</code> implementation uses this level of synchronization. 112 * <P> 113 * At higher levels of synchronization, referred to as pessimistic concurrency, 114 * the writer take steps to avoid conflicts by setting locks. Setting locks 115 * can vary from setting a lock on a single row to setting a lock on a table 116 * or the entire data source. The level of synchronization is therefore a tradeoff 117 * between the ability of users to access the data source concurrently and the ability 118 * of the writer to keep the data in the <code>RowSet</code> object and its data source 119 * synchronized. 120 * <P> 121 * It is a requirement that all disconnected <code>RowSet</code> objects 122 * (<code>CachedRowSet</code>, <code>FilteredRowSet</code>, <code>JoinRowSet</code>, 123 * and <code>WebRowSet</code> objects) obtain their <code>SyncProvider</code> objects 124 * from the <code>SyncFactory</code> mechanism. 125 * <P> 126 * The reference implementation (RI) provides two synchronization providers. 127 * <UL> 128 * <LI><b><code>RIOptimisticProvider</code></b> <br> 129 * The default provider that the <code>SyncFactory</code> instance will 130 * supply to a disconnected <code>RowSet</code> object when no provider 131 * implementation is specified.<BR> 132 * This synchronization provider uses an optimistic concurrency model, 133 * assuming that there will be few conflicts among users 134 * who are accessing the same data in a database. It avoids 135 * using locks; rather, it checks to see if there is a conflict 136 * before trying to synchronize the <code>RowSet</code> object and the 137 * data source. If there is a conflict, it does nothing, meaning that 138 * changes to the <code>RowSet</code> object are not persisted to the data 139 * source. 140 * <LI><B><code>RIXMLProvider</code></B> <BR> 141 * A synchronization provider that can be used with a 142 * <code>WebRowSet</code> object, which is a rowset that can be written 143 * in XML format or read from XML format. The 144 * <code>RIXMLProvider</code> implementation does no checking at all for 145 * conflicts and simply writes any updated data in the 146 * <code>WebRowSet</code> object to the underlying data source. 147 * <code>WebRowSet</code> objects use this provider when they are 148 * dealing with XML data. 149 * </UL> 150 * 151 * These <code>SyncProvider</code> implementations 152 * are bundled with the reference implementation, which makes them always available to 153 * <code>RowSet</code> implementations. 154 * <code>SyncProvider</code> implementations make themselves available by being 155 * registered with the <code>SyncFactory</code> singleton. When a <code>RowSet</code> 156 * object requests a provider, by specifying it in the constructor or as an argument to the 157 * <code>CachedRowSet</code> method <code>setSyncProvider</code>, 158 * the <code>SyncFactory</code> singleton 159 * checks to see if the requested provider has been registered with it. 160 * If it has, the <code>SyncFactory</code> creates an instance of it and passes it to the 161 * requesting <code>RowSet</code> object. 162 * If the <code>SyncProvider</code> implementation that is specified has not been registered, 163 * the <code>SyncFactory</code> singleton causes a <code>SyncFactoryException</code> object 164 * to be thrown. If no provider is specified, 165 * the <code>SyncFactory</code> singleton will create an instance of the default 166 * provider implementation, <code>RIOptimisticProvider</code>, 167 * and pass it to the requesting <code>RowSet</code> object. 168 * 169 * <P> 170 * If a <code>WebRowSet</code> object does not specify a provider in its constructor, the 171 * <code>SyncFactory</code> will give it an instance of <code>RIOptimisticProvider</code>. 172 * However, the constructor for <code>WebRowSet</code> is implemented to set the provider 173 * to the <code>RIXMLProvider</code>, which reads and writes a <code>RowSet</code> object 174 * in XML format. 175 * <P> 176 * See the <a href="SyncProvider.html">SyncProvider</a> class 177 * specification for further details. 178 * <p> 179 * Vendors may develop a <code>SyncProvider</code> implementation with any one of the possible 180 * levels of synchronization, thus giving <code>RowSet</code> objects a choice of 181 * synchronization mechanisms. 182 * 183 * <h3><a id="arch">2.0 Service Provider Interface Architecture</a></h3> 184 * <b>2.1 Overview</b> 185 * <p> 186 * The Service Provider Interface provides a pluggable mechanism by which 187 * <code>SyncProvider</code> implementations can be registered and then generated when 188 * required. The lazy reference mechanism employed by the <code>SyncFactory</code> limits 189 * unnecessary resource consumption by not creating an instance until it is 190 * required by a disconnected 191 * <code>RowSet</code> object. The <code>SyncFactory</code> class also provides 192 * a standard API to configure logging options and streams that <b>may</b> be provided 193 * by a particular <code>SyncProvider</code> implementation. 194 * <p> 195 * <b>2.2 Registering with the <code>SyncFactory</code></b> 196 * <p> 197 * A third party <code>SyncProvider</code> implementation must be registered with the 198 * <code>SyncFactory</code> in order for a disconnected <code>RowSet</code> object 199 * to obtain it and thereby use its <code>javax.sql.RowSetReader</code> and 200 * <code>javax.sql.RowSetWriter</code> 201 * implementations. The following registration mechanisms are available to all 202 * <code>SyncProvider</code> implementations: 203 * <ul> 204 * <li><b>System properties</b> - Properties set at the command line. These 205 * properties are set at run time and apply system-wide per invocation of the Java 206 * application. See the section <a href="#reldocs">"Related Documentation"</a> 207 * further related information. 208 * 209 * <li><b>Property Files</b> - Properties specified in a standard property file. 210 * This can be specified using a System Property or by modifying a standard 211 * property file located in the platform run-time. The 212 * reference implementation of this technology includes a standard property 213 * file than can be edited to add additional <code>SyncProvider</code> objects. 214 * 215 * <li><b>JNDI Context</b> - Available providers can be registered on a JNDI 216 * context. The <code>SyncFactory</code> will attempt to load <code>SyncProvider</code> 217 * objects bound to the context and register them with the factory. This 218 * context must be supplied to the <code>SyncFactory</code> for the mechanism to 219 * function correctly. 220 * </ul> 221 * <p> 222 * Details on how to specify the system properties or properties in a property file 223 * and how to configure the JNDI Context are explained in detail in the 224 * <a href="SyncFactory.html"><code>SyncFactory</code></a> class description. 225 * <p> 226 * <b>2.3 SyncFactory Provider Instance Generation Policies</b> 227 * <p> 228 * The <code>SyncFactory</code> generates a requested <code>SyncProvider</code> 229 * object if the provider has been correctly registered. The 230 * following policies are adhered to when either a disconnected <code>RowSet</code> object 231 * is instantiated with a specified <code>SyncProvider</code> implementation or is 232 * reconfigured at runtime with an alternative <code>SyncProvider</code> object. 233 * <ul> 234 * <li> If a <code>SyncProvider</code> object is specified and the <code>SyncFactory</code> 235 * contains <i>no</i> reference to the provider, a <code>SyncFactoryException</code> is 236 * thrown. 237 * 238 * <li> If a <code>SyncProvider</code> object is specified and the <code>SyncFactory</code> 239 * contains a reference to the provider, the requested provider is supplied. 240 * 241 * <li> If no <code>SyncProvider</code> object is specified, the reference 242 * implementation provider <code>RIOptimisticProvider</code> is supplied. 243 * </ul> 244 * <p> 245 * These policies are explored in more detail in the <a href="SyncFactory.html"> 246 * <code>SyncFactory</code></a> class. 247 * 248 * <h3><a id="impl">3.0 SyncProvider Implementer's Guide</a></h3> 249 * 250 * <b>3.1 Requirements</b> 251 * <p> 252 * A compliant <code>SyncProvider</code> implementation that is fully pluggable 253 * into the <code>SyncFactory</code> <b>must</b> extend and implement all 254 * abstract methods in the <a href="SyncProvider.html"><code>SyncProvider</code></a> 255 * class. In addition, an implementation <b>must</b> determine the 256 * grade, locking and updatable view capabilities defined in the 257 * <code>SyncProvider</code> class definition. One or more of the 258 * <code>SyncProvider</code> description criteria <b>must</b> be supported. It 259 * is expected that vendor implementations will offer a range of grade, locking, and 260 * updatable view capabilities. 261 * <p> 262 * Furthermore, the <code>SyncProvider</code> naming convention <b>must</b> be followed as 263 * detailed in the <a href="SyncProvider.html"><code>SyncProvider</code></a> class 264 * description. 265 * <p> 266 * <b>3.2 Grades</b> 267 * <p> 268 * JSR 114 defines a set of grades to describe the quality of synchronization 269 * a <code>SyncProvider</code> object can offer a disconnected <code>RowSet</code> 270 * object. These grades are listed from the lowest quality of service to the highest. 271 * <ul> 272 * <li><b>GRADE_NONE</b> - No synchronization with the originating data source is 273 * provided. A <code>SyncProvider</code> implementation returning this grade will simply 274 * attempt to write any data that has changed in the <code>RowSet</code> object to the 275 *underlying data source, overwriting whatever is there. No attempt is made to compare 276 * original values with current values to see if there is a conflict. The 277 * <code>RIXMLProvider</code> is implemented with this grade. 278 * 279 * <li><b>GRADE_CHECK_MODIFIED_AT_COMMIT</b> - A low grade of optimistic synchronization. 280 * A <code>SyncProvider</code> implementation returning this grade 281 * will check for conflicts in rows that have changed between the last synchronization 282 * and the current synchronization under way. Any changes in the originating data source 283 * that have been modified will not be reflected in the disconnected <code>RowSet</code> 284 * object. If there are no conflicts, changes in the <code>RowSet</code> object will be 285 * written to the data source. If there are conflicts, no changes are written. 286 * The <code>RIOptimisticProvider</code> implementation uses this grade. 287 * 288 * <li><b>GRADE_CHECK_ALL_AT_COMMIT</b> - A high grade of optimistic synchronization. 289 * A <code>SyncProvider</code> implementation returning this grade 290 * will check all rows, including rows that have not changed in the disconnected 291 * <code>RowSet</code> object. In this way, any changes to rows in the underlying 292 * data source will be reflected in the disconnected <code>RowSet</code> object 293 * when the synchronization finishes successfully. 294 * 295 * <li><b>GRADE_LOCK_WHEN_MODIFIED</b> - A pessimistic grade of synchronization. 296 * <code>SyncProvider</code> implementations returning this grade will lock 297 * the row in the originating data source that corresponds to the row being changed 298 * in the <code>RowSet</code> object to reduce the possibility of other 299 * processes modifying the same data in the data source. 300 * 301 * <li><b>GRADE_LOCK_WHEN_LOADED</b> - A higher pessimistic synchronization grade. 302 * A <code>SyncProvider</code> implementation returning this grade will lock 303 * the entire view and/or table affected by the original query used to 304 * populate a <code>RowSet</code> object. 305 * </ul> 306 * <p> 307 * <b>3.3 Locks</b> 308 * <p> 309 * JSR 114 defines a set of constants that specify whether any locks have been 310 * placed on a <code>RowSet</code> object's underlying data source and, if so, 311 * on which constructs the locks are placed. These locks will remain on the data 312 * source while the <code>RowSet</code> object is disconnected from the data source. 313 * <P> 314 * These constants <b>should</b> be considered complementary to the 315 * grade constants. The default setting for the majority of grade settings requires 316 * that no data source locks remain when a <code>RowSet</code> object is disconnected 317 * from its data source. 318 * The grades <code>GRADE_LOCK_WHEN_MODIFIED</code> and 319 * <code>GRADE_LOCK_WHEN_LOADED</code> allow a disconnected <code>RowSet</code> object 320 * to have a fine-grained control over the degree of locking. 321 * <ul> 322 * <li><b>DATASOURCE_NO_LOCK</b> - No locks remain on the originating data source. 323 * This is the default lock setting for all <code>SyncProvider</code> implementations 324 * unless otherwise directed by a <code>RowSet</code> object. 325 * 326 * <li><b>DATASOURCE_ROW_LOCK</b> - A lock is placed on the rows that are touched by 327 * the original SQL query used to populate the <code>RowSet</code> object. 328 * 329 * <li><b>DATASOURCE_TABLE_LOCK</b> - A lock is placed on all tables that are touched 330 * by the query that was used to populate the <code>RowSet</code> object. 331 * 332 * <li><b>DATASOURCE_DB_LOCK</b> 333 * A lock is placed on the entire data source that is used by the <code>RowSet</code> 334 * object. 335 * </ul> 336 * <p> 337 * <b>3.4 Updatable Views</b> 338 * <p> 339 * A <code>RowSet</code> object may be populated with data from an SQL <code>VIEW</code>. 340 * The following constants indicate whether a <code>SyncProvider</code> object can 341 * update data in the table or tables from which the <code>VIEW</code> was derived. 342 * <ul> 343 * <li><b>UPDATABLE_VIEW_SYNC</b> 344 * Indicates that a <code>SyncProvider</code> implementation supports synchronization 345 * to the table or tables from which the SQL <code>VIEW</code> used to populate 346 * a <code>RowSet</code> object is derived. 347 * 348 * <li><b>NONUPDATABLE_VIEW_SYNC</b> 349 * Indicates that a <code>SyncProvider</code> implementation does <b>not</b> support 350 * synchronization to the table or tables from which the SQL <code>VIEW</code> 351 * used to populate a <code>RowSet</code> object is derived. 352 * </ul> 353 * <p> 354 * <b>3.5 Usage of <code>SyncProvider</code> Grading and Locking</b> 355 * <p> 356 * In the example below, the reference <code>CachedRowSetImpl</code> implementation 357 * reconfigures its current <code>SyncProvider</code> object by calling the 358 * <code>setSyncProvider</code> method.<br> 359 * 360 * <PRE> 361 * CachedRowSetImpl crs = new CachedRowSetImpl(); 362 * crs.setSyncProvider("com.foo.bar.HASyncProvider"); 363 * </PRE> 364 * An application can retrieve the <code>SyncProvider</code> object currently in use 365 * by a disconnected <code>RowSet</code> object. It can also retrieve the 366 * grade of synchronization with which the provider was implemented and the degree of 367 * locking currently in use. In addition, an application has the flexibility to set 368 * the degree of locking to be used, which can increase the possibilities for successful 369 * synchronization. These operation are shown in the following code fragment. 370 * <PRE> 371 * SyncProvider sync = crs.getSyncProvider(); 372 * 373 * switch (sync.getProviderGrade()) { 374 * case: SyncProvider.GRADE_CHECK_ALL_AT_COMMIT 375 * //A high grade of optimistic synchronization 376 * break; 377 * case: SyncProvider.GRADE_CHECK_MODIFIED_AT_COMMIT 378 * //A low grade of optimistic synchronization 379 * break; 380 * case: SyncProvider.GRADE_LOCK_WHEN_LOADED 381 * // A pessimistic synchronization grade 382 * break; 383 * case: SyncProvider.GRADE_LOCK_WHEN_MODIFIED 384 * // A pessimistic synchronization grade 385 * break; 386 * case: SyncProvider.GRADE_NONE 387 * // No synchronization with the originating data source provided 388 * break; 389 * } 390 * 391 * switch (sync.getDataSourcLock() { 392 * case: SyncProvider.DATASOURCE_DB_LOCK 393 * // A lock is placed on the entire datasource that is used by the 394 * // <code>RowSet</code> object 395 * break; 396 * 397 * case: SyncProvider.DATASOURCE_NO_LOCK 398 * // No locks remain on the originating data source. 399 * break; 400 * 401 * case: SyncProvider.DATASOURCE_ROW_LOCK 402 * // A lock is placed on the rows that are touched by the original 403 * // SQL statement used to populate 404 * // the RowSet object that is using the SyncProvider 405 * break; 406 * 407 * case: DATASOURCE_TABLE_LOCK 408 * // A lock is placed on all tables that are touched by the original 409 * // SQL statement used to populated 410 * // the RowSet object that is using the SyncProvider 411 * break; 412 * 413 * </PRE> 414 * It is also possible using the static utility method in the 415 * <code>SyncFactory</code> class to determine the list of <code>SyncProvider</code> 416 * implementations currently registered with the <code>SyncFactory</code>. 417 * 418 * <pre> 419 * Enumeration e = SyncFactory.getRegisteredProviders(); 420 * </pre> 421 * 422 * 423 * <h3><a id="resolving">4.0 Resolving Synchronization Conflicts</a></h3> 424 * 425 * The interface <code>SyncResolver</code> provides a way for an application to 426 * decide manually what to do when a conflict occurs. When the <code>CachedRowSet</code> 427 * method <code>acceptChanges</code> finishes and has detected one or more conflicts, 428 * it throws a <code>SyncProviderException</code> object. An application can 429 * catch the exception and 430 * have it retrieve a <code>SyncResolver</code> object by calling the method 431 * <code>SyncProviderException.getSyncResolver()</code>. 432 * <P> 433 * A <code>SyncResolver</code> object, which is a special kind of 434 * <code>CachedRowSet</code> object or 435 * a <code>JdbcRowSet</code> object that has implemented the <code>SyncResolver</code> 436 * interface, examines the conflicts row by row. It is a duplicate of the 437 * <code>RowSet</code> object being synchronized except that it contains only the data 438 * from the data source this is causing a conflict. All of the other column values are 439 * set to <code>null</code>. To navigate from one conflict value to another, a 440 * <code>SyncResolver</code> object provides the methods <code>nextConflict</code> and 441 * <code>previousConflict</code>. 442 * <P> 443 * The <code>SyncResolver</code> interface also 444 * provides methods for doing the following: 445 * <UL> 446 * <LI>finding out whether the conflict involved an update, a delete, or an insert 447 * <LI>getting the value in the data source that caused the conflict 448 * <LI>setting the value that should be in the data source if it needs to be changed 449 * or setting the value that should be in the <code>RowSet</code> object if it needs 450 * to be changed 451 * </UL> 452 * <P> 453 * When the <code>CachedRowSet</code> method <code>acceptChanges</code> is called, it 454 * delegates to the <code>RowSet</code> object's <code>SyncProvider</code> object. 455 * How the writer provided by that <code>SyncProvider</code> object is implemented 456 * determines what level (grade) of checking for conflicts will be done. After all 457 * checking for conflicts is completed and one or more conflicts has been found, the method 458 * <code>acceptChanges</code> throws a <code>SyncProviderException</code> object. The 459 * application can catch the exception and use it to obtain a <code>SyncResolver</code> object. 460 * <P> 461 * The application can then use <code>SyncResolver</code> methods to get information 462 * about each conflict and decide what to do. If the application logic or the user 463 * decides that a value in the <code>RowSet</code> object should be the one to 464 * persist, the application or user can overwrite the data source value with it. 465 * <P> 466 * The comment for the <code>SyncResolver</code> interface has more detail. 467 * 468 * <h3><a id="relspec">5.0 Related Specifications</a></h3> 469 * <ul> 470 * <li><a href="http://docs.oracle.com/javase/jndi/tutorial/index.html">JNDI</a> 471 * <li><a href="{@docRoot}/java.logging/java/util/logging/package-summary.html">Java Logging 472 * APIs</a> 473 * </ul> 474 * <h3><a id="reldocs">6.0 Related Documentation</a></h3> 475 * <ul> 476 * <li><a href="http://docs.oracle.com/javase/tutorial/jdbc/">DataSource for JDBC 477 * Connections</a> 478 * </ul> 479 */ 480 package javax.sql.rowset.spi;