package com.bagri.xqj; import static com.bagri.core.Constants.*; import java.io.PrintWriter; import java.lang.reflect.Constructor; import java.sql.Connection; import java.util.Map; import java.util.Properties; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQDataSource; import javax.xml.xquery.XQException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.bagri.core.api.SchemaRepository; import com.bagri.core.xquery.api.XQProcessor; /** * @author Denis Sukhoroslov * @see javax.xml.xquery.XQDataSource */ public class BagriXQDataSource implements XQDataSource { private static final Logger logger = LoggerFactory.getLogger(BagriXQDataSource.class); public static final String HOST = "host"; public static final String PORT = "port"; public static final String SCHEMA = "schema"; public static final String USER = "user"; public static final String PASSWORD = "password"; public static final String ADDRESS = "address"; public static final String TRANSACTIONAL = "transactional"; public static final String XQ_PROCESSOR = "processor"; public static final String XDM_REPOSITORY = "repository"; // TODO: implement some relevant writer which will do logging private PrintWriter writer; protected Properties properties = new Properties(); // DataSource initialization: init query processor // connection -> set processor // processor -> set Repository // Repository -> initialize dictionary, factory public BagriXQDataSource() { // ... //properties.put(HOST, "localhost"); //properties.put(PORT, "5701"); properties.put(ADDRESS, "localhost:5701"); properties.put(USER, "anonymous"); properties.put(PASSWORD, "password"); properties.put(SCHEMA, "default"); properties.put(TRANSACTIONAL, "false"); properties.put(pn_client_fetchSize, "50"); properties.put(pn_client_loginTimeout, "30"); properties.put(pn_client_bufferSize, "32"); properties.put(pn_client_connectAttempts, "3"); properties.put(XQ_PROCESSOR, ""); //"com.bagri.xquery.saxon.XQProcessorClient"); properties.put(XDM_REPOSITORY, ""); //"com.bagri.client.hazelcast.impl.SchemaRepositoryImpl"); } /** {@inheritDoc} */ @Override public XQConnection getConnection() throws XQException { String address = getAddress(); logger.trace("getConnection. creating new connection for address: {}", address); return initConnection(null); } /** {@inheritDoc} */ @Override public XQConnection getConnection(Connection connection) throws XQException { // will work only if the Connection provided is an // another connection to the underlying cache throw new XQException("method not supported"); } /** * {@inheritDoc} */ @Override public XQConnection getConnection(String username, String password) throws XQException { String address = getAddress(); logger.trace("getConnection. creating new connection for address: {}; user: {}", address, username); properties.put(USER, username); properties.put(PASSWORD, password); return initConnection(username); } private String getAddress() { String address = properties.getProperty(ADDRESS); if (address == null) { address = properties.getProperty(HOST) + ":" + properties.getProperty(PORT); } return address; } protected boolean isTransactional() { String transactional = properties.getProperty(TRANSACTIONAL); return ("true".equalsIgnoreCase(transactional)); } private Object makeInstance(String propName) throws XQException { String className = properties.getProperty(propName); if (className == null || className.trim().length() == 0) { return null; } try { Class<?> procClass = Class.forName(className); Object instance = procClass.newInstance(); return instance; } catch (ClassNotFoundException ex) { throw new XQException("Unknown " + propName + " class: " + className); } catch (InstantiationException | IllegalAccessException ex) { throw new XQException("Cannot instantiate " + className + ". Exception: " + ex.getMessage()); } } private Object initRepository(BagriXQConnection connect) throws XQException { String className = properties.getProperty(XDM_REPOSITORY); if (className == null || className.trim().length() == 0) { return null; } try { Class<?> procClass = Class.forName(className); try { Constructor<?> init = procClass.getConstructor(Properties.class); if (init != null) { Properties props = new Properties(); props.putAll(properties); props.put(pn_client_dataFactory, connect); return init.newInstance(props); } } catch (Exception ex) { logger.error("initRepository. error creating Repository of type " + className + " with Properties. Falling back to default constructor", ex); } return procClass.newInstance(); } catch (ClassNotFoundException ex) { throw new XQException("Unknown class: " + className); } catch (InstantiationException | IllegalAccessException ex) { throw new XQException("Cannot instantiate " + className + ". Exception: " + ex.getMessage()); } } protected BagriXQConnection createConnection(String username) { return new BagriXQConnection(username, isTransactional()); } private XQConnection initConnection(String username) throws XQException { BagriXQConnection connect = createConnection(username); Object xqp = makeInstance(XQ_PROCESSOR); if (xqp != null) { if (xqp instanceof XQProcessor) { connect.setProcessor((XQProcessor) xqp); ((XQProcessor) xqp).setXQDataFactory(connect); Object xdm = initRepository(connect); if (xdm != null) { if (xdm instanceof SchemaRepository) { ((XQProcessor) xqp).setRepository((SchemaRepository) xdm); } else { throw new XQException("Specified Repository class does not implement XDMRepository interface: " + properties.getProperty(XDM_REPOSITORY)); } } } else { throw new XQException("Specified XQ Processor class does not implement XQProcessor interface: " + properties.getProperty(XQ_PROCESSOR)); } } return connect; } /** * {@inheritDoc} */ @Override public PrintWriter getLogWriter() throws XQException { return writer; } /** * {@inheritDoc} */ @Override public int getLoginTimeout() throws XQException { return Integer.parseInt(properties.getProperty(pn_client_loginTimeout)); } /** * {@inheritDoc} */ @Override public String getProperty(String name) throws XQException { if (name == null) { throw new XQException("name is null"); } if (!properties.containsKey(name)) { throw new XQException("unknown property: " + name); } return properties.getProperty(name); } /** * {@inheritDoc} */ @Override public String[] getSupportedPropertyNames() { return properties.keySet().toArray(new String[properties.size()]); } /** * {@inheritDoc} */ @Override public void setLogWriter(PrintWriter writer) throws XQException { this.writer = writer; } /** * {@inheritDoc} */ @Override public void setLoginTimeout(int timeout) throws XQException { properties.setProperty(pn_client_loginTimeout, String.valueOf(timeout)); } /** {@inheritDoc} */ @Override public void setProperties(Properties props) throws XQException { if (props == null) { throw new XQException("Properties are null"); } for (Map.Entry prop: props.entrySet()) { setProperty((String) prop.getKey(), (String) prop.getValue()); } } /** * {@inheritDoc} * @see javax.xml.xquery.XQDataSource#setProperty(String, String) */ @Override public void setProperty(String name, String value) throws XQException { if (name == null) { throw new XQException("name is null"); } if (!properties.containsKey(name)) { throw new XQException("unknown property: " + name); } properties.setProperty(name, value); } }