/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ro.nextreports.designer.datasource; import java.io.*; import java.sql.Connection; import java.util.ArrayList; import java.util.List; import ro.nextreports.engine.ReleaseInfoAdapter; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; import ro.nextreports.designer.Globals; import ro.nextreports.designer.datasource.exception.*; import ro.nextreports.designer.persistence.FileReportPersistence; import ro.nextreports.designer.util.I18NSupport; import ro.nextreports.designer.util.Show; import sun.misc.BASE64Encoder; import sun.misc.BASE64Decoder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Created by IntelliJ IDEA. * User: mihai.panaitescu * Date: May 15, 2006 * Time: 2:24:47 PM */ public class DefaultDataSourceManager implements DataSourceManager { protected List<DataSource> sources; private String version = ""; private static DefaultDataSourceManager instance; // parameter passed to application : contains the xml data sources as a string // // the application must be called like this : // next-reports.exe -J-Dnextreports.datasources="..." // where the value is the xml datasources content private static String DATASOURCES_PARAMETER = "nextreports.datasources"; protected static String datasourcesXml = System.getProperty(DATASOURCES_PARAMETER); public static final String DATASOURCES_FILE = "datasource.xml"; private static Log LOG = LogFactory.getLog(DefaultDataSourceManager.class); public static DefaultDataSourceManager getInstance() { if (instance == null) { if (datasourcesXml == null) { instance = new DefaultDataSourceManager(); } else { instance = new MemoryDataSourceManager(); } } return instance; } protected DefaultDataSourceManager() { sources = new ArrayList<DataSource>(); } public void addDataSource(DataSource source) throws NonUniqueException { DataSource found = getDataSource(source.getName()); if (found != null) { throw new NonUniqueException("A data source with name " + source.getName() + " already exists!"); } sources.add(source); } public void modifyDataSource(DataSource oldSource, DataSource newSource) throws ModificationException, NonUniqueException { if ((oldSource == null) || (newSource == null)) { throw new IllegalArgumentException("Source parameters cannot be null."); } if (newSource.getStatus() == DataSourceType.CONNECTED) { throw new IllegalArgumentException("New Data Source " + newSource.getName() + " cannot have status connected!"); } if (!oldSource.getName().toLowerCase().equals(newSource.getName().toLowerCase())) { DataSource found = getDataSource(newSource.getName()); if (found != null) { throw new NonUniqueException("A datasource with name '" + newSource.getName() + "' exists."); } } DataSource source = getDataSource(oldSource.getName()); if (source != null) { if (source.getStatus() == DataSourceType.CONNECTED) { throw new ModificationException("Data Source " + source.getName() + " is connected!"); } source.setName(newSource.getName()); source.setType(newSource.getType()); source.setDriver(newSource.getDriver()); source.setUrl(newSource.getUrl()); source.setUser(newSource.getUser()); source.setPassword(newSource.getPassword()); source.setStatus(newSource.getStatus()); source.setProperties(newSource.getProperties()); } } public void removeDataSource(String name) throws NotFoundException { DataSource sourceFound = getDataSource(name); if (sourceFound != null) { sources.remove(sourceFound); } else { throw new NotFoundException("DataSource " + name + " not found."); } } public List<DataSource> getDataSources() { return sources; } public List<DataSource> getDataSources(String driver) { List<DataSource> result = new ArrayList<DataSource>(); for (DataSource ds : sources) { if (ds.getDriver().equals(driver)) { result.add(ds); } } return result; } public DataSource getDataSource(String name) { if (name == null) { return null; } for (DataSource source : sources) { if (source.getName().toLowerCase().equals(name.toLowerCase())) { return source; } } return null; } public void connect(String name) throws ConnectionException, NotFoundException { DataSource source = getDataSource(name); if (source == null) { throw new NotFoundException("DataSource " + name + " not found."); } Connection c = Globals.getConnection(); if (c != null) { throw new ConnectionException("There is a connection active!"); } Globals.createConnection(source); source.setStatus(DataSourceType.CONNECTED); Globals.getMainFrame().setStatusBarMessage("<html>" + I18NSupport.getString("datasource.active") + " <b>" + source.getName() + "</b></html>"); } public void disconnect(String name) throws NotFoundException { DataSource source = getDataSource(name); if (source == null) { throw new NotFoundException("DataSource " + name + " not found."); } Connection c; try { c = Globals.getConnection(); if (c != null) { c.close(); } } catch (Exception e) { e.printStackTrace(); LOG.error(e.getMessage(), e); } finally { c = null; Globals.setConnection(c); Globals.clearDialect(); source.setStatus(DataSourceType.DISCONNECTED); Globals.getMainFrame().setStatusBarMessage(""); } } public DataSource getConnectedDataSource() { for (DataSource source : sources) { if (source.getStatus() == DataSourceType.CONNECTED) { return source; } } return null; } protected static XStream createXStream() { XStream xstream = new XStream(new DomDriver("UTF-8")); xstream.alias("datasource", DataSource.class); xstream.alias("datasources", DataSources.class); xstream.addImplicitCollection(DataSources.class, "list"); xstream.useAttributeFor(DataSources.class, "version"); return xstream; } /////// password encryption ////////////////////////////////////////// private static final String key = "Encrypt"; private static final String CHARSET_NAME = "UTF-8"; private String encrypt(String plainText) throws EncryptionException { try { String enc = encryptDecrypt(plainText, 1); return new BASE64Encoder().encode(enc.getBytes(CHARSET_NAME)); } catch (UnsupportedEncodingException e) { throw new EncryptionException("Encryption Failed!"); } } private String decrypt(String cipherText) throws EncryptionException { try { byte[] bytes = new BASE64Decoder().decodeBuffer(cipherText); cipherText = new String(bytes, 0, bytes.length, CHARSET_NAME); return encryptDecrypt(cipherText, -1); } catch (IOException e) { throw new EncryptionException("Decryption Failed!"); } } private String encryptDecrypt(String sourceText, int oper) { int keyLength = key.length(); int sourceLength = sourceText.length(); char[] result = new char[sourceLength]; for (int i = 0; i < sourceLength; i++) { int keyPoz = i % keyLength; char currentSource = sourceText.charAt(i); char currentKey = key.charAt(keyPoz); int source = (int) currentSource % 128; //get the ASCII code of the input char int key = (int) currentKey % 128; //get the ASCII code of the key char int newValue = (source + (oper * key)) % 128; //add/substract them into a new ASCII code if (newValue < 0) { newValue = 128 + newValue; //if the result is <0 make it positive } result[i] = (char) newValue; //store the coresponding char } return new String(result); } private void encryptSourcePasswords() throws EncryptionException { for (DataSource source : sources) { try { source.setPassword(encrypt(source.getPassword())); } catch (EncryptionException ex) { throw new EncryptionException("Encryption failed for datasource " + source.getName() + " !"); } } } protected void decryptSourcePasswords() throws EncryptionException { decryptSourcePasswords(sources); } private void decryptSourcePasswords(List<DataSource> sources) throws EncryptionException { for (DataSource source : sources) { try { source.setPassword(decrypt(source.getPassword())); } catch (EncryptionException ex) { throw new EncryptionException("Decryption failed for datasource " + source.getName() + " !"); } } } ////////////////////////////////////////////////////////////////////// public boolean save() { return save(Globals.USER_DATA_DIR + "/" + DATASOURCES_FILE, sources); } public boolean save(String file, List<DataSource> sources) { XStream xstream = createXStream(); FileOutputStream fos = null; try { try { fos = new FileOutputStream(file); } catch (FileNotFoundException e1) { try { (new File(file)).createNewFile(); } catch (IOException e) { Show.error(I18NSupport.getString("datasource.save.error", file)); return false; } } encryptSourcePasswords(); DataSources ds = new DataSources(new ArrayList<DataSource>(sources), ReleaseInfoAdapter.getVersionNumber()); xstream.toXML(ds, fos); fos.flush(); decryptSourcePasswords(); return true; } catch (EncryptionException ex) { Show.error(ex); return false; } catch (Exception e1) { e1.printStackTrace(); Show.error(e1); LOG.error(e1.getMessage(), e1); return false; } finally { if (fos != null) { try { fos.close(); } catch (IOException e1) { e1.printStackTrace(); } } } } public void load() { XStream xstream = createXStream(); FileInputStream fis = null; InputStreamReader reader = null; try { fis = new FileInputStream(Globals.USER_DATA_DIR + "/" + DATASOURCES_FILE); reader = new InputStreamReader(fis, "UTF-8"); DataSources ds = (DataSources) xstream.fromXML(reader); sources = ds.getList(); version = ds.getVersion(); if (sources.size() > Globals.getDataSources()) { int toDelete = sources.size() - Globals.getDataSources(); for (int i = 0; i < toDelete; i++) { sources.remove(0); } } decryptSourcePasswords(); for (DataSource s : sources) { (new File(FileReportPersistence.CONNECTIONS_DIR + File.separator + s.getName() + File.separator + FileReportPersistence.QUERIES_FOLDER)).mkdirs(); (new File(FileReportPersistence.CONNECTIONS_DIR + File.separator + s.getName() + File.separator + FileReportPersistence.REPORTS_FOLDER)).mkdirs(); (new File(FileReportPersistence.CONNECTIONS_DIR + File.separator + s.getName() + File.separator + FileReportPersistence.CHARTS_FOLDER)).mkdirs(); } } catch (FileNotFoundException e1) { // nothing to do -> file is created when first data source is created } catch (EncryptionException ex) { Show.error(ex); } catch (Exception e1) { e1.printStackTrace(); LOG.error(e1.getMessage(), e1); } finally { if (fis != null) { try { fis.close(); } catch (IOException e1) { e1.printStackTrace(); } } } } public List<DataSource> load(String file) { List<DataSource> result = new ArrayList<DataSource>(); XStream xstream = createXStream(); FileInputStream fis = null; InputStreamReader reader = null; try { fis = new FileInputStream(file); reader = new InputStreamReader(fis, "UTF-8"); DataSources ds = (DataSources) xstream.fromXML(reader); result = ds.getList(); decryptSourcePasswords(result); } catch (FileNotFoundException e1) { Show.error(e1); } catch (EncryptionException ex) { Show.error(ex); } catch (Exception e1) { Show.error(I18NSupport.getString("import.data.source.error")); e1.printStackTrace(); LOG.error(e1.getMessage(), e1); } finally { if (fis != null) { try { fis.close(); } catch (IOException e1) { e1.printStackTrace(); } } } return result; } public static boolean memoryDataSources() { return datasourcesXml != null; } public String getVersion() { return version; } public String getVersion(String file) { XStream xstream = createXStream(); FileInputStream fis = null; InputStreamReader reader = null; String version = ""; try { fis = new FileInputStream(file); reader = new InputStreamReader(fis, "UTF-8"); try { DataSources ds = (DataSources) xstream.fromXML(reader); version = ds.getVersion(); } catch (ClassCastException cce) { // older versions do not have version field! } } catch (FileNotFoundException e1) { Show.error(e1); } catch (Exception e1) { e1.printStackTrace(); LOG.error(e1.getMessage(), e1); } finally { if (fis != null) { try { fis.close(); } catch (IOException e1) { e1.printStackTrace(); } } } return version; } }