001/*
002 *  Copyright 2015 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.core.datasource.dbtype;
017
018import java.io.InputStream;
019import java.io.UnsupportedEncodingException;
020import java.sql.PreparedStatement;
021import java.sql.ResultSet;
022import java.sql.SQLException;
023import java.util.HashMap;
024import java.util.Map;
025import java.util.Set;
026
027import org.ametys.runtime.i18n.I18nizableText;
028import org.ametys.runtime.plugin.component.AbstractThreadSafeComponentExtensionPoint;
029
030/**
031 * This class is in charge to load and initialize the {@link SQLDatabaseType} 
032 */
033public class SQLDatabaseTypeExtensionPoint extends AbstractThreadSafeComponentExtensionPoint<SQLDatabaseType>
034{
035    /** Avalon Role */
036    public static final String ROLE = SQLDatabaseTypeExtensionPoint.class.getName();
037    
038    @Override
039    public void initializeExtensions() throws Exception
040    {
041        super.initializeExtensions();
042        
043        for (String databaseTypeId : getExtensionsIds())
044        {
045            SQLDatabaseType databaseType = getExtension(databaseTypeId);
046            
047            try
048            {
049                Class.forName(databaseType.getDriver());
050            }
051            catch (ClassNotFoundException e)
052            {
053                getLogger().warn("JDBC Driver cannot be found for extension '" + databaseTypeId + "' with classname '" + databaseType.getDriver() + "'");
054            }
055        }
056    }
057    
058    /**
059     * Get the SQL database types with their label
060     * @return the SQL database types with their label
061     */
062    public Map<String, I18nizableText> getSQLDatabaseTypes()
063    {
064        Map<String, I18nizableText> db = new HashMap<>();
065        
066        Set<String> extensionsIds = getExtensionsIds();
067        for (String extensionId : extensionsIds)
068        {
069            SQLDatabaseType dbType = getExtension(extensionId);
070            db.put(extensionId, dbType.getLabel());
071        }
072        
073        return db;
074    }
075    
076    /**
077     * Some db systems requires the table names to be escaped
078     * @param dbType The identifier of the db type used
079     * @param tableNameToEscape The non-null table name
080     * @return The escaped table name or at least the table name if no escape is required. Or null if the dbtype is unknown.
081     */
082    public String languageEscapeTableName(String dbType, String tableNameToEscape)
083    {
084        if (hasExtension(dbType))
085        {
086            return getExtension(dbType).languageEscapeTableName(tableNameToEscape);
087        }
088        else
089        {
090            return null;
091        }
092    }
093    
094    /**
095     * Add a limit/offset element to the given query
096     * @param dbType The identifier of the db type used
097     * @param queryToLimit The sql query that will be amended
098     * @param limit The max number of the results to return
099     * @param offset The initial offset of the results to return
100     * @return The initial query amended to handle the limit and offset. Or null if the dbtype is unknown.
101     */
102    public String languageLimitQuery(String dbType, String queryToLimit, String limit, String offset)
103    {
104        if (hasExtension(dbType))
105        {
106            return getExtension(dbType).languageLimitQuery(queryToLimit, limit, offset);
107        }
108        else
109        {
110            return null;
111        }
112    }
113    
114    /**
115     * Get the InputStream to read a blob
116     * @param dbType The identifier of the db type used
117     * @param resultSet the result set containing the blob.
118     * @param columnName column
119     * @return an InputStream to read the blob
120     * @throws SQLException if the columnLabel is not valid; if a database access error occurs or this method is called on a closed result set
121     */
122    public InputStream getBlob(String dbType, ResultSet resultSet, String columnName) throws SQLException
123    {
124        if (hasExtension(dbType))
125        {
126            return getExtension(dbType).getBlob(resultSet, columnName);
127        }
128        else
129        {
130            return null;
131        }
132    }
133    
134    /**
135     * Get the InputStream to read a blob
136     * @param dbType The identifier of the db type used
137     * @param resultSet the result set containing the blob.
138     * @param pos column position
139     * @return an InputStream to read the blob
140     * @throws SQLException if the columnLabel is not valid; if a database access error occurs or this method is called on a closed result set
141     */
142    public InputStream getBlob(String dbType, ResultSet resultSet, int pos) throws SQLException
143    {
144        if (hasExtension(dbType))
145        {
146            return getExtension(dbType).getBlob(resultSet, pos);
147        }
148        else
149        {
150            return null;
151        }
152    }
153    
154    /**
155     * Set an String into a blob
156     * @param dbType The identifier of the db type used
157     * @param statement The satement where the blob will be set
158     * @param pos position in the statement
159     * @param blob String representing the blob
160     * @throws SQLException if the columnLabel is not valid; if a database access error occurs or this method is called on a closed result set
161     * @throws UnsupportedEncodingException if UTF-8 is not supported
162     * @throws IllegalArgumentException if the dbType is not found
163     */
164    public void setBlob(String dbType, PreparedStatement statement, int pos, String blob) throws SQLException, UnsupportedEncodingException, IllegalArgumentException
165    {
166        if (hasExtension(dbType))
167        {
168            getExtension(dbType).setBlob(statement, pos, blob);
169        }
170        else
171        {
172            throw new IllegalArgumentException("Database of type '" + dbType + "' is not supported");
173        }
174    }
175    
176    /**
177     * Set an array of bytes (UTF-8 encoded) into a blob, if you want to pass a String, you can use {@link #setBlob(String, PreparedStatement, int, String)}
178     * @param dbType The identifier of the db type used
179     * @param statement The satement where the blob will be set
180     * @param pos position in the statement
181     * @param bytes byte[] representing the blob, in UTF-8
182     * @throws SQLException if the columnLabel is not valid; if a database access error occurs or this method is called on a closed result set
183     * @throws IllegalArgumentException if the dbType is not found
184     */
185    public void setBlob(String dbType, PreparedStatement statement, int pos, byte[] bytes) throws SQLException, IllegalArgumentException
186    {
187        if (hasExtension(dbType))
188        {
189            getExtension(dbType).setBlob(statement, pos, bytes);
190        }
191        else
192        {
193            throw new IllegalArgumentException("Database of type '" + dbType + "' is not supported");
194        }
195    }
196    
197
198    
199    /**
200     * Set an array of bytes (UTF-8 encoded) into a blob, if you want to pass a String, you can use {@link #setBlob(String, PreparedStatement, int, String)}
201     * @param dbType The identifier of the db type used
202     * @param statement The satement where the blob will be set
203     * @param pos position in the statement
204     * @param is inputStream to put in the blob
205     * @param length length of the stream
206     * @throws SQLException if the columnLabel is not valid; if a database access error occurs or this method is called on a closed result set
207     * @throws IllegalArgumentException if the dbType is not found
208     */
209    public void setBlob(String dbType, PreparedStatement statement, int pos, InputStream is, long length) throws SQLException, IllegalArgumentException
210    {
211        if (hasExtension(dbType))
212        {
213            getExtension(dbType).setBlob(statement, pos, is, length);
214        }
215        else
216        {
217            throw new IllegalArgumentException("Database of type '" + dbType + "' is not supported");
218        }
219    }
220}