1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 package com.sun.star.sdbcx.comp.postgresql;
23 
24 import java.util.ArrayList;
25 import java.util.concurrent.atomic.AtomicBoolean;
26 
27 import com.sun.star.beans.PropertyValue;
28 import com.sun.star.lang.DisposedException;
29 import com.sun.star.lang.XServiceInfo;
30 import com.sun.star.lang.XSingleComponentFactory;
31 import com.sun.star.lib.uno.helper.ComponentBase;
32 import com.sun.star.lib.uno.helper.Factory;
33 import com.sun.star.sdbc.DriverPropertyInfo;
34 import com.sun.star.sdbc.SQLException;
35 import com.sun.star.sdbc.XConnection;
36 import com.sun.star.sdbc.XDriver;
37 import com.sun.star.sdbc.XDriverManager;
38 import com.sun.star.sdbcx.XDataDefinitionSupplier;
39 import com.sun.star.sdbcx.XTablesSupplier;
40 import com.sun.star.sdbcx.comp.postgresql.util.SharedResources;
41 import com.sun.star.sdbcx.comp.postgresql.util.StandardSQLState;
42 import com.sun.star.uno.Exception;
43 import com.sun.star.uno.UnoRuntime;
44 import com.sun.star.uno.XComponentContext;
45 
46 public class PostgresqlDriver extends ComponentBase implements XServiceInfo, XDriver, XDataDefinitionSupplier {
47     private static String[] services = new String[] {
48             "com.sun.star.sdbc.Driver",
49             "com.sun.star.sdbcx.Driver"
50     };
51     private XComponentContext componentContext;
52     private AtomicBoolean isDisposed = new AtomicBoolean(false);
53 
54     public static XSingleComponentFactory __getComponentFactory(String implName) {
55         XSingleComponentFactory xSingleComponentFactory = null;
56         if (implName.equals(getImplementationNameStatic())) {
57             xSingleComponentFactory = Factory.createComponentFactory(PostgresqlDriver.class,
58                     getImplementationNameStatic(), services);
59         }
60         return xSingleComponentFactory;
61     }
62 
63     public PostgresqlDriver(XComponentContext componentContext) {
64         this.componentContext = componentContext;
65         SharedResources.registerClient(componentContext);
66     }
67 
68     private static String getImplementationNameStatic() {
69         return PostgresqlDriver.class.getName();
70     }
71 
72     // XComponent:
73 
74     @Override
75     protected void postDisposing() {
76         isDisposed.set(true);
77         componentContext = null;
78         SharedResources.revokeClient();
79     }
80 
81     private void checkDisposed() throws DisposedException {
82         if (isDisposed.get()) {
83             throw new DisposedException();
84         }
85     }
86 
87     // XServiceInfo:
88 
89     @Override
90     public String getImplementationName() {
91         return getImplementationNameStatic();
92     }
93 
94     @Override
95     public String[] getSupportedServiceNames() {
96         return services.clone();
97     }
98 
99     @Override
100     public boolean supportsService(String serviceName) {
101         for (String service : services) {
102             if (service.equals(serviceName)) {
103                 return true;
104             }
105         }
106         return false;
107     }
108 
109     // XDriver:
110 
111     @Override
112     public boolean acceptsURL(String url) throws SQLException {
113         return url.startsWith("sdbc:postgresql:jdbc:");
114     }
115 
116     @Override
117     public XConnection connect(String url, PropertyValue[] info) throws SQLException {
118         checkDisposed();
119         XConnection connection = null;
120         if (acceptsURL(url)) {
121             String jdbcUrl = transformUrl(url);
122             System.out.println("Using SDBC URL " + url + " and JDBC URL " + jdbcUrl);
123 
124             try {
125                 Object driverManagerObject = componentContext.getServiceManager().createInstanceWithContext(
126                         "com.sun.star.sdbc.DriverManager", componentContext);
127                 XDriverManager driverManager = UnoRuntime.queryInterface(XDriverManager.class, driverManagerObject);
128 
129                 ArrayList<PropertyValue> properties = new ArrayList<>();
130                 boolean haveJavaClass = false;
131                 for (PropertyValue property : info) {
132                     if (property.Name.equals("JavaDriverClass")) {
133                         haveJavaClass = true;
134                     }
135                     properties.add(property);
136                 }
137                 if (!haveJavaClass) {
138                     PropertyValue javaClassProperty = new PropertyValue();
139                     javaClassProperty.Name = "JavaDriverClass";
140                     javaClassProperty.Value = "org.postgresql.Driver";
141                     properties.add(javaClassProperty);
142                 }
143                 PropertyValue[] jdbcInfo = properties.toArray(new PropertyValue[properties.size()]);
144 
145                 connection = driverManager.getConnectionWithInfo(jdbcUrl, jdbcInfo);
146                 if (connection != null) {
147                     connection = new PostgresqlConnection(connection, url);
148                 }
149             } catch (SQLException sqlException) {
150                 throw sqlException;
151             } catch (Exception exception) {
152                 throw new SQLException(exception.getMessage(), this, StandardSQLState.SQL_UNABLE_TO_CONNECT.text(), 0, exception);
153             }
154         }
155         return connection;
156     }
157 
158     @Override
159     public int getMajorVersion() {
160         return 1;
161     }
162 
163     @Override
164     public int getMinorVersion() {
165         return 0;
166     }
167 
168     @Override
169     public DriverPropertyInfo[] getPropertyInfo(String url, PropertyValue[] info) throws SQLException {
170         if (!acceptsURL(url)) {
171             return new DriverPropertyInfo[0];
172         }
173         return new DriverPropertyInfo [] {
174                 new DriverPropertyInfo("JavaClassName", "The JDBC driver class name.", true,
175                         "com.postgresql.Driver", new String[0]),
176         };
177     }
178 
179     private static String transformUrl(String url) {
180         // 012345678901234567890
181         // sdbc:postgresql:jdbc:
182         return "jdbc:postgresql:" + url.substring(21);
183     }
184 
185     // XDataDefinitionSupplier:
186 
187     public XTablesSupplier getDataDefinitionByConnection(XConnection connection) throws SQLException {
188         checkDisposed();
189         return new PostgresqlCatalog((PostgresqlConnection)connection);
190     }
191 
192     public XTablesSupplier getDataDefinitionByURL(String url, PropertyValue[] info) throws SQLException {
193         checkDisposed();
194         if (!acceptsURL(url)) {
195             throw new SQLException(); // FIXME
196         }
197         return getDataDefinitionByConnection(connect(url, info));
198     }
199 }
200