MySQL Connector/Java 8.0.8-dmr has been released

Dear MySQL users,

MySQL Connector/J 8.0.8 Development Release is a development milestone
release for the 8.0.x series.

This release includes the following new features and changes, also
described in more detail on

https://dev.mysql.com/doc/relnotes/connector-j/8.0/en/news-8-0-8.html

MySQL Connectors and other MySQL client tools and applications now
synchronize the first digit of their version number with the (highest)
MySQL server version they support.
This change makes it easy and intuitive to decide which client version
to use for which server version.

As always, we recommend that you check the “CHANGES” file in the download
archive to be aware of changes in behavior that might affect your application.

To download MySQL Connector/J 8.0.8 dmr, see the “Development
Releases” tab at http://dev.mysql.com/downloads/connector/j/

Enjoy!


Changes in MySQL Connector/J 8.0.8 (2017-09-28, Development Milestone)

   Version 8.0.8 Development Milestone is the latest development
   release of the 8.0 branch of MySQL Connector/J, providing an
   insight into upcoming features. It is suitable for use with
   MySQL Server versions 5.5, 5.6, 5.7, and 8.0. It supports the
   Java Database Connectivity (JDBC) 4.2 API.

   Functionality Added or Changed

     * Packaging: RPM and Debian packages for installing
       Connector/J are now available from the Connector/J
       Download page
       (http://dev.mysql.com/downloads/connector/j/).

     * X DevAPI: Connector/J has implemented a new interface of
       the X Dev API that allows the retrieving, adding,
       removing, and updating of persistent session continuation
       data. The implementation includes the following:

          + A SessionConfig object that holds the information
            for a session configuration data set.

          + A PersistenceHandler interface that allows custom
            implementations of persistence handlers.

          + A PasswordHandler interface that allows custom
            implementations of password handling code.

          + A SessionConfigManager class for editing and
            fetching Sessionconfig objects, and defining
            instances of the PersistenceHandler and
            PasswordHandler.
       See MySQL Connector/J X DevAPI Reference
       (http://dev.mysql.com/doc/dev/connector-j) for more
       details.

     * X DevAPI: A new connection property, xdevapi.auth, has
       been added for specifying the authentication mechanism
       for connections using the X Protocol. Allowed values are
       MYSQL41, PLAIN, and EXTERNAL. See the entry for the new
       property in Configuration Properties
 (http://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-configuration-properties.html)
       for details. 

     * X DevAPI: To support row locks
(http://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html)
       for the find() method of the X DevAPI, the
       FindStatement and the SelecStatement interfaces have been
       extended with the following methods:

          + lockExclusive(), which works like SELECT ... FOR
            UPDATE for relational tables.

          + lockShared(), which works like the SELECT ... LOCK
            IN SHARED MODE (for MySQL 5.7) or SELECT ... FOR
            SHARE (for MySQL 8.0) for relational tables.
       See MySQL Connector/J X DevAPI Reference
       (http://dev.mysql.com/doc/dev/connector-j) for more
       details.

     * X DevAPI: Connector/J now supports the expanded syntax
       for the IN and NOT IN operator, which can check if a
       sub-expression is contained inside another one; for
       example:
       // For documents
       coll.find("$.b IN [100,101,102]").execute();
       coll.find("'some text with 5432' in $.a").execute();
       coll.find("1 in [1, 2, 4]").execute();
       coll.find("{'a': 3} not in {'a': 1, 'b': 2}").execute();
       // For relational tables
       tbl.select().where("3 not in [1, 2, 4]").execute();
       tbl.select().where("'qqq' not in $.a").execute();
       tbl.select().where("{'a': 1} in {'a': 1, 'b': 2}").execute();


     * X DevAPI: A number of changes have been implemented for
       the "drop" methods for the X DevAPI:

          + Removed dropCollection(schemaName, collectionName)
            and dropTable(schemaName, tableName) from Session.

          + Added dropCollection(collectionName) and
            dropTable(tableName) to Schema.

          + Schema.dropView() now executes immediately and
            returns void; also, the ViewDrop interface has been
            removed.

          + Collection.dropIndex() now executes immediately and
            returns void; also the DropCollectionIndexStatement
            interface has been removed.

          + The "drop" methods now succeed even if the objects
            to be dropped do not exist.

     * Conversion from the MySQL TIME data to java.sql.Date is
       now supported. In the past, a getDate() retrieving data
       from a TIME column would throw an SQLException. Now, such
       a retrieval returns a java.sql.Date object containing the
       time value expressed in number of milliseconds from the
       Java epoch; also returned is the warning: "Date part does
       not exist in SQL TIME field, thus it is set to January 1,
       1970 GMT while converting to java.sql.Date." (Bug
       #26750807)

     * A new connection property, enabledTLSProtocols, can now
       be used to override the default restrictions on the TLS
       versions to be used for connections, which are determined
       by the version of the MySQL Server that is being
       connected to. By providing a comma-separated list of
       values to this option (for example,
       "TLSv1,TLSv1.1,TLSv1.2") users can, for example, prevent
       connections from using older TLS version, or allow
       connections to use TLS versions only supported by a
       user-compiled MySQL Server. See the entry for the new
       property in Configuration Properties
(http://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-configuration-properties.html)
       for details.
       Thanks to Todd Farmer for contributing the code. (Bug
       #26646676)

     * Updated the timezone mappings using the latest IANA and
       CLDR time zone databases. (Bug #25946965)

     * A new option for the loadBalancingStrategy connection
       property called serverAffinity has been added. The
       servers listed in the new connection property
       serverAffinityOrder (which should be a subset of the
       servers in the host list of the connection URL) are
       contacted in the order they are listed until a server is
       available or until the list of servers is exhausted, at
       which point a random load-balancing strategy is used with
       the hosts not listed by serverAffinityOrder. See
       descriptions for loadBalancingStrategy and
       serverAffinityOrder in Configuration Properties
(http://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-configuration-properties.html)
       for details. (Bug #20182108)

   Bugs Fixed

     * Important Change: Following the changes in MySQL Server
       8.0.3, the system variables tx_isolation and tx_read_only
       have been replaced with transaction_isolation and
       transaction_read_only in the code of Connector/J. Users
       should update Connector/J to this latest release in order
       to connect to MySQL 8.0.3. They should also make the same
       adjustments to their own applications if they use the old
       variables in their codes. (Bug #26440544)

     * X DevAPI: Calling schema.dropView() with a null argument
       resulted in a NullPointerException. (Bug #26750807)

     * X DevAPI: When dropCollection() was applied on a null
       collection, a NullPointerException occurred. (Bug
       #26393132)

     * When using cached server-side prepared statements, a
       memory leak occurred as references to opened statements
       were being kept while the statements were being decached;
       it happened when either the close() method has been
       called twice on a statement, or when there were
       conflicting cache entries for a statement and the older
       entry had not been closed and removed from the opened
       statement list. This fix makes sure the statements are
       properly closed in both cases. Thanks to Eduard Gurskiy
       for contributing to the fix. (Bug #26633984, Bug #87429)

     * The regression test for Bug#63800 failed because the
       default value of the system variable
       explicit_defaults_for_timestamp of MySQL Server has been
       changed since release 8.0.2. The test has been adjusted
       to take the change into consideration. (Bug #26501245)

     * Running callable statements against MySQL Server 8.0
       resulted in the SQLException: ResultSet is from UPDATE.
       No Data. (Bug #26259384)

     * Secure JDBC connections did not fall back to the default
       truststore when a custom one was not provided. (Bug
       #26243128)

     * In com/mysql/jdbc/ServerPreparedStatement.java, the
       arguments resultSetType and resultSetConcurrency for a
       call of Connection.preparedStatement() were swapped. (Bug
       #25874048, Bug #85885)

     * Some JDBC proxied objects were missing the proper
       handlings of the equals() methods, thus even comparison
       of one of these proxied objects to its own self with
       equals() yielded false. This patch introduces proper
       handlings for the equals() method in all the relevant
       proxies. (Bug #21931572, Bug #78313)

     * A server-side prepared statement was not closed when the
       same statement was being prepared again while the
       original statement was being cached. This was caused by
       the silent replacement of the cache entry of the old
       statement by the new. When this happened repeatedly, it
       caused eventually the complaint that
       max_prepared_stmt_count was exceeded. This fix makes sure
       that when a cache entry for a statement replaces an older
       one, the older statement is immediately closed. (Bug
       #20066806, Bug #74932)


On behalf of Oracle MySQL Release Team
Balasubramanian Kandasamy

MySQL Connector/J 5.1.40 has been released

I’m pleased to announce the newest MySQL Connector/J 5.1 Maintenance Release.

As usual, MySQL Connector/J 5.1 can be downloaded from the official distribution channels MySQL Downloads and The Central Repository. The commercially licensed version is available for download at My Oracle Support.

Please don’t forget to consult the CHANGES file in the download archive and/or the release notes page to know what is new and if there are any changes that might affect your applications.

MySQL Connector/J 5.1.40 is the official JDBC driver for MySQL databases and, as such, we are continuously working to make it better, more reliable and faster. This new version delivers several bug fixes and upgrades. This is the current recommend  version and you should upgrade to it as soon as possible.

I’d like to highlight the most relevant fixes and improvements in this release:

Recovered & new features

Previous versions used to silently disable local transaction states management (connection property useLocalTransactionState=true) when server side query cache was enable. This used to be workaround for a know server bug that it’s long time gone. The workaround in Connector/J side, though, survived till these days. I’m pretty sure that the effects will be almost unnoticed but certainly this helps empowering the developer and provides better control over the Connector.

The XA errors mapping in Connector/J was updated with the missing error codes that the server may throw back.

MySQL Fabric support issues

Connector/J 5.1 maintains support for MySQL Fabric, as such, this release comes with a couple fixes to it. Fabric connections are especially prone to problems as they rely on both a connection to a Fabric node and multiple connections to MySQL servers while having to be able to refresh themselves to topology changes, failures and such. A couple of issues caused by communication failures to the Fabric node are now fixed.

Continuous improvement of MySQL data types support

The JSON data type is relatively new in Connector/J. As such, every now and then there is something that needs to be fixed or adjusted. This time it was an encoding issue observed when the JSON strings contained non Latin characters. Additionally, the specific combination of updatable result sets with cursor based fetches was missing the support for the JSON type.

Getting data from BIT columns as numeric values was behaving inconsistently when binary values and ASCII values of numbers matched. As a result, instead of the expected value, it was occurring an extra conversion to String before the data was returned. Also fixed in this release.

Improved internals

Although we aim to, it’s almost impossible to guarantee that the code is free from memory leaks, deadlocks, NPEs and so on. A few of those where caused by some bugs that are now fixed.

Under certain situations the exception interceptor mechanism was being triggered twice. This, not only caused an unwanted additional  processing, but also was hiding the real cause that triggered the interceptor.

Client-side caching of prepared statements while using server-side prepared statements requires extra care because it can easily be a source of memory leaks, both on client and server sides. In this particular scenario, setting a statement as non-poolable was causing a never ending number of prepared statements on server and never deallocated. Per se, this wasn’t a problem for the driver because it is prepared to switch-over to client prepared statements as soon as it is unable to create more on the server, but it wasn’t the desired behavior for sure.

Transactions states managed locally got fixed for when there were exceptions while on the middle of one. Without the fix the rollback and commit wasn’t operating as expected.

The database connection URL syntax got support for several extensions over the year. With that also increased the corner cases that its parsers have to deal with. A couple of them were fixed in this release, specifically a NPE and an incompatibility with host names starting with the word “address”.

Thanks!

Enjoy this new Connector/J release. Get the most out of it by reading its official documentation or by getting the developer’s support directly from the forum channel.

Special thanks to Dong Song Ling and Ryosuke Yamazaki for their valuable contributions.

Thank you all for your support and feedback, and keep in touch!

On behalf of the MySQL Connector/J Team

MySQL Connector/J 6.0.4 has been released

We are pleased to announce the next development release of MySQL Connector/J 6.0 which supports both JDBC 4.2 API and the new X DevAPI.

MySQL Connector/J 6.0.4 can be downloaded from the official distribution channels MySQL Downloads (see the “Development Releases” tab) and The Central repository. MySQL Connector/J source is also available on GitHub.

As always, we recommend that you check the CHANGES file in the download archive and/or the release notes to be aware of changes in behavior that might affect your application.

For documentation please visit the MySQL Connector/J 6.0 Developer Guide.

Note that Connector/J 6.0.4 is a milestone release and not intended for production usage.

I’d like to highlight the most important changes in this release:

X DevAPI connection string

The prefix used in connection string for X DevAPI is now unified between MySQL connectors. The “mysql:x:” we used in previous Connector/J 6.0 releases doesn’t work anymore, please use the “mysqlx:” one to establish XSession:

X DevAPI support for views

The com.mysql.cj.api.x.Table interface now represents both database tables and views. Schema.getTables() returns a list of Table objects for each existing database Table and View. Schema.getTable(name) also returns a Table object if the object with a given name is a View.

A new Table interface method was added:

The com.mysql.cj.api.x.View interface existed in previous Connector/J 6.0 releases isn’t available in Connector/J 6.0.4.

MySQL server compliance

MySQL Connector/J 6.0.4 is suitable for use with MySQL server versions 5.5, 5.6, and 5.7 via Java Database Connectivity (JDBC) 4.2 API.

Due to changes in X Protocol implementation MySQL Connector/J 6.0.4 requires at least MySQL 5.7.14 server when working via X DevAPI.

Thanks!

Enjoy this new Connector/J and thank you all for your support!

On behalf of the MySQL Connector/J Team.

MySQL Connector/J 5.1.39 has been released

I’m pleased to announce that MySQL Connector/J 5.1.39 Maintenance Release is now generally available.

MySQL Connector/J can be downloaded from the official distribution channels MySQL Downloads and The Central Repository. The commercially licensed version is available for download at My Oracle Support.

As always, we recommend that you check the CHANGES file in the download archive and/or the release notes page to know what is new and if there are any changes that might affect your applications.

With MySQL Connector/J 5.1.39 you get the continuously improved JDBC driver for MySQL databases, now including several fixes and upgrades. Even if you didn’t face any of the fixed issues, we do recommend that you upgrade to the latest version.

I’d like to highlight the most relevant fixes and improvements in this release:

MySQL Fabric support related issues

As you well know by now, MySQL Fabric support in Connector/J is built on its generic multi-host connections feature, more specifically on replication connections. This feature, along with load-balanced connections support, have received several improvements all over the latest releases. This time, we fixed and tuned up a few incoherences that were spotted on a few corner cases, namely when, due to the Fabric management process, the list of known hosts in an active connection could actually become empty for a short period of time while performing the fail-over, and so causing a whole set of new problems. As a consequence of these developments, we introduced a new connection property:

loadBalanceHostRemovalGracePeriod. This property sets the time, in milliseconds, that the driver should wait for a load-balanced connection to be allowed to switch to a different host when the currently active one is being removed, either by an internal process such as in a Fabric or a replication connection, or by dynamic hosts management, through the JMX interfaces the driver provides. Default value is 15000 milliseconds.

Additional improvements and fixes

  • Unnecessary exception throwing and capturing when establishing connections.
  • Temporal data corruption in prepared statements under special circumstances.
  • Incorrect JDBC 4.2 Java 8 Time support when using cached prepared statements.
  • Application server using multiple class loaders could face a NullPointerException when setting up the driver’s time zone configurations.
  • Exception caused by missing metadata information in updatable result sets.
  • Concurrent modification issue on closing statements and connections concurrently from different threads.
  • Maintenance fixes in the test suite.
  • Source code formatting, Copyright notice fixes.
  • Build script adjustments, new code coverage reports, compiler warnings cleanup.
  • Manifest fixed to expose Fabric connections.
  • Support for latest changes in MySQL protocol, introduced in MySQL 5.7, namely the deprecation of EOF packets.

Thanks!

Enjoy this new release of Connector/J and stay tuned for the next releases as there is still much to deliver.

Get the most out of this Connector/J release by reading its official documentation or by getting the developer’s support directly from the forum channel.

Thank you all for your support and keep in touch!

On behalf of the MySQL Connector/J Team

MySQL Connector/J 5.1.38 has been released

I’m pleased to announce that MySQL Connector/J 5.1.38 Maintenance Release is now generally available.

MySQL Connector/J can be downloaded from the official distribution channels MySQL Downloads and The Central repository. The commercially licensed version is available for download at My Oracle Support.

As always, we recommend that you check the CHANGES file in the download archive and/or the release notes to be aware of changes in behavior that might affect your application.

MySQL Connector/J 5.1.38, although released shortly after its predecessor, includes several important fixes and improvements. Most of them related to MySQL Fabric, multi-host replication aware connections support and support for TLSv1.2 and new encryption defaults. Even if you don’t require such features, we do recommend the upgrade to the latest version.

I’d like to highlight some of the most relevant fixes and improvements in this release:

MySQL Fabric and Multi-Host Replication Connections Revision

MySQL Fabric support in Connector/J is based on multi-host replication aware connections and the ability to dynamically manage server groups. Most of the server groups management is done automatically and, possibly, concurrently. The combination of all these features was never thoroughly used and stressed as much as now and the consequence is that they were effectively in need of some improvements.

This release ships with a fully re-factored multi-host replication aware connections support, which now inherits from the same base architecture as the remaining multi-host connections alternatives, the fail-over connections and load-balanced connections. This architecture provides a layered connection support structure and an improved statement execution routing model that effectively determines the correct physical connection to use at execution time, also fixing, by this way, a couple of existing bugs. The synchronization model in the server groups management was revised as well in order to overcome a few known thread deadlock situations. As a direct result the fail-over in MySQL Fabric support is now way more robust.

In the process of the improvements made in multi-host replication aware connections, two new connection properties were added:

allowSlaveDownConnections. This property sets the behavior for establishing replication aware connections when no slave hosts available. While, previously, this would result in a failed connection attempt, now we can define the behavior we prefer. This property takes a boolean value:

readFromMasterWhenNoSlaves. This property sets the behavior for the situations where, at run-time, all slave hosts in a replication aware connection become unavailable. The alternatives “should it fail?”, the only possible outcome before introducing this property, or “should the master host(s) be used in their place?”, are now available to the developer. Mind that when you set the option to use the master host(s), they will be used in read-only state as if they were slave hosts. Also mind that setting this property to true might, transparently, incur in extra load to the master host(s). This property takes a boolean value:

Security Compliance and Improvements

In its way of complying with the up-to-date security regulations and requirements, MySQL server 5.7 is now shipped with SSL/TLS enabled by default and any clients connecting to it should make use of such data protection features by default as well. Following this path, Connector/J 5.1.38 prioritizes the usage of SSL/TLS when establishing connections to this server. The missing support for TLSv1.2 and TLSv1.1 was additionally included in this release.

Connector/J now attempts to use the highest security layer available at run-time, starting from TLSv1.2 and, at the end, providing the best encryption system possible for the moment. This obviously depends on the MySQL server version we are connecting to and on the JVM version in use. In some situations it may be somewhat complex to find a compatible set of cyphers that can be used in both ends and some tweaks or adjustments could be required. The connection property enabledSSLCipherSuites may be a good companion in such cases.

Additional Bug Fixes

This release also includes a few other minor bug fixes. Although not especially relevant, these fixes help improving the overall quality of this Connector/J release.

Thanks!

Thank you all for your support. Enjoy this new Connector/J and keep in touch!

On behalf of the MySQL Connector/J Team.

MySQL Connector/J 5.1.37 has been released

I’m pleased to announce: MySQL Connector/J 5.1.37 Maintenance Release is now available.

MySQL Connector/J can be downloaded from the official distribution channels MySQL Downloads and The Central repository. Commercial license version is available for download at My Oracle Support.

As always, we recommend that you check the “CHANGES” file in the
download archive and/or the release notes to be aware of changes in behavior that might affect your application.

MySQL Connector/J 5.1.37 includes several bug fixes and other improvements. I’d like to highlight just a few:

Support for JDBC 4.2

Connector/J now provides implementations for pretty much all new JDBC 4.2 methods, namely for large update counts and max rows support.

The other big change is the support for the new temporal classes from java.time package. LocalDate, LocalDateTime, LocalTime are fully supported and can now be used in the multiple versions of setObject(...) and getObject(...) methods. They deliver results very similar to their counterparts, Date, Time and Timestamp respectively. The types OffsetDateTime and OffsetTime are partially supported via conversion to *CHAR types as MySQL doesn’t provide support for temporal data containing time zone information and, thus, doesn’t support the new TIME_WITH_TIMEZONE and TIMESTAMP_WITH_TIMEZONE JDBC types as well.

As a consequence to this upgrade, Connector/J 5.1.37 and future versions require Java 8 for its building process. We maintained, however, full compatibility with the already supported Java versions – Java 5 and above, Thus, this is a seamless replacement for the previous drivers versions you may be using in your projects.

New Connection Properties

sendFractionalSeconds. This property controls whether fractional seconds in timestamps are to be truncated on the client side or to be sent to the server side where they may be subject to rounding. It takes a boolean value:

Rounding fractional seconds may lead to undesired situations, especially when this results in apparently “big” temporal leaps, such as advancing a timestamp value to the next minute, day or even year. Many times this is not the required behavior for applications and setting this property to false safely cancels it.

Mind that this option applies only to prepared statements, callable statements and updatable result sets.

enableEscapeProcessing. This property, introduced as part of the support for JDBC 4.2, sets the default escape processing behavior for Statement objects. It takes a boolean value:

The method Statement.setEscapeProcessing() allows to set the escape processing behavior for individual statements. This method’s documentation refers that the connection property escapeProcessing can be used to set the default behavior, however, in Connector/J, this property is actually named enableEscapeProcessing.

Note that the default escape processing behavior in prepared statements is set by the long time available property processEscapeCodesForPrepStmts.

Changes in the Building Process

With JDBC 4.2 support comes a dependency on the Java 8 compiler and with it some changes in the building from source procedure. The documentation contains all the details you need to know but, the fast shortcut is that the previous ant property com.mysql.jdbc.jdk6 was upgraded to com.mysql.jdbc.jdk8 and holds the obvious reference to the JDK 8 path.

The optional property com.mysql.jdbc.java6.rtjar was added as well and is used to obtain the most accurate byte codes for every single JDBC implementation contained in this driver. You are not required to use it unless you are building for production, in which case we recommend you to set it too.

Bug Fixes

Several bug fixes were introduced aiming to improve your Connector/J experience.

We were able to fix a few things in the meta data structures, a time zone related adjustment, a couple of null point exceptions and corrected the right type of exception, all observed in very specific situations. We improved the authentication procedure, making it more robust. And, finally, we tweaked the driver to be fully compliant with latest MySQL server releases.

Thanks!

This release contains some contributions from end users. Special thanks to Jie Han and KwonNam for their valuable contributions.

Thank you all for your support as well. Enjoy this new Connector/J and keep in touch!

On behalf of the MySQL Connector/J Team.

Connector/J moves to Git

I’m pleased to announce that Connector/J has a new home.

Just as several other MySQL products, Connector/J source code management moved to Git and, pretty much as expected, to GitHub. Our reasoning is nothing else than listening to our users demands and trying to follow best trends and practices. There was nothing significantly wrong with Bazaar and Launchpad, as they served us well for the last seven years. It was just time to move on.

Rest assured, all will work as before, no complications no hassles. Our public GitHub repository will expose Connector/J source code as it is in the latest generally available (GA) release, as it has been for the last years.

From now on you will find Connector/J source code in the well known Git repository hosting service, GitHub, at mysql-connector-j under the umbrella of MySQL organization. Other MySQL products will follow in time. This repository contains all history since Connector/J early days so nothing was lost. Those who are used to our old launchpad repository will only have to change tools.

Hands-on

GitHub allows you to explore source code, project history, get to know about contributions and a lot more. But you probably already know all of this anyway.

So, to get the Connector/J source code you can just execute the following command in your preferred shell or command prompt:

You can also fetch the code through SSH protocol, using Subversion or simply download it as a zip file. Obviously, in order for you to execute git commands, you’ll have to have it installed in your computer. Just follow the official getting started guide if you don’t have it yet.

Building MySQL Connector/J 5.1 from source

Some time ago I have blogged about building Connector/J from source code. Nothing changes in this post, except for the replacement of Bazaar and Launchpad by Git and GitHub respectively and the  bzr  command that is replaced by the  git  command mentioned above.

We love to hear from you

As always, don’t forget to use our official channels to report us your wishes, findings or just ask for help when you need it. We can be found at MySQL Bugs database or MySQL Connector/JDBC and Java forum. Thank you!

Welcome to Connector/J on Git!
Farewell Bazaar. Farewell Launchpad. Thank you for the 7 years of good services.