/* * Copyright 2009 NCHOVY * * Licensed 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 org.krakenapps.jpa; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.Set; import javax.persistence.PersistenceException; import org.krakenapps.api.BundleManager; import org.krakenapps.api.MavenResolveException; import org.krakenapps.api.ProgressMonitor; import org.krakenapps.api.Script; import org.krakenapps.api.ScriptArgument; import org.krakenapps.api.ScriptContext; import org.krakenapps.api.ScriptUsage; import org.osgi.framework.BundleException; /** * Kraken Script for JPA control * * @author xeraph * */ public class JpaScript implements Script { private JpaService jpa; private ScriptContext context; private BundleManager bundleManager; /** * Created with the specific JPA service * * @param jpa * the JPA service */ public JpaScript(JpaService jpa, BundleManager bundleManager) { this.jpa = jpa; this.bundleManager = bundleManager; } /** * Set script context */ @Override public void setScriptContext(ScriptContext context) { this.context = context; } /** * List all registered JPA entity manager factories * * @param args * empty array */ @ScriptUsage(description = "List all registered JPA entity manager factories") public void list(String[] args) { context.println("JPA Profiles"); context.println("---------------"); Set<String> factoryNames = jpa.getProfileNames(); for (String factoryName : factoryNames) { context.println(factoryName); } } @ScriptUsage(description = "List all registered JPA entity manager factories", arguments = { @ScriptArgument(name = "factory name", type = "string", description = "Print all properties of the specified entity manager factory") }) public void props(String[] args) { String factoryName = args[0]; JpaProfile config = jpa.getProfile(factoryName); if (config == null) { context.println("entity manager factory not found"); return; } Properties props = config.getProperties(); for (Object key : props.keySet()) { context.printf("%s = %s\n", key, props.get(key)); } context.println(""); } @ScriptUsage(description = "Create and register new entity manager factory", arguments = { @ScriptArgument(name = "Bundle ID", type = "int", description = "Bundle that contains JPA model classes and kraken-jpa configurations"), @ScriptArgument(name = "Entity Manager Factory Name", type = "string", description = "Alias for entity manager factory") }) public void configure(String[] args) { int bundleId = Integer.parseInt(args[0]); String factoryName = args[1]; Properties props = new Properties(); try { context.println("Config Templates"); context.println("------------------"); int i = 1; List<DatabaseConfigTemplate> templates = getConfigTemplates(); for (DatabaseConfigTemplate t : templates) context.println("[" + (i++) + "] " + t.toString()); context.print("select? "); int selected = Integer.valueOf(context.readLine()); if (selected < 1 && selected > templates.size()) { context.println("invalid number"); return; } DatabaseConfigTemplate t = templates.get(selected - 1); context.print("Host (default: localhost)? "); String host = context.readLine(); context.print("Database? "); String db = context.readLine().trim(); if (db.isEmpty()) { context.println("=> database name is empty"); return; } context.print("User? "); String user = context.readLine().trim(); if (user.isEmpty()) context.println("=> user will be JPA config default"); context.print("Password? "); String password = context.readPassword().trim(); if (password.isEmpty()) context.println("=> password will be JPA config default"); t.set(props, host, db, user, password); jpa.registerEntityManagerFactory(factoryName, props, bundleId); context.println(factoryName + " registered"); } catch (NumberFormatException e) { context.println("invalid number format"); } catch (InterruptedException e) { context.println(""); context.println("interrupted"); } catch (Exception e) { context.println(e.getMessage()); } } private List<DatabaseConfigTemplate> getConfigTemplates() { File jpaDir = new File(System.getProperty("kraken.data.dir"), "kraken-jpa"); jpaDir.mkdirs(); String jpaDataPath = jpaDir.getAbsolutePath(); List<DatabaseConfigTemplate> configs = new ArrayList<JpaScript.DatabaseConfigTemplate>(); configs.add(new DatabaseConfigTemplate("MySQL", "com.mysql.jdbc.Driver", "org.hibernate.dialect.MySQLInnoDBDialect", "jdbc:mysql://$host/$db?useUnicode=true&characterEncoding=utf8")); configs.add(new DatabaseConfigTemplate("PostgreSQL", "org.postgresql.Driver", "org.hibernate.dialect.PostgreSQLDialect", "jdbc:postgresql://$host/$db")); configs.add(new DatabaseConfigTemplate("HSQLDB", "org.hsqldb.jdbcDriver", "org.hibernate.dialect.HSQLDialect", "jdbc:hsqldb:" + jpaDataPath + "/$db;shutdown=true")); return configs; } public void installDriver(String[] args) { try { context.println("Database"); context.println("-------------"); List<JDBCDriverBundleInfo> infos = getDriverInfos(); int i = 1; for (JDBCDriverBundleInfo info : infos) context.println("[" + (i++) + "] " + info.toString()); context.print("select? "); int selected = Integer.valueOf(context.readLine()); if (selected < 1 && selected > infos.size()) { context.println("invalid number"); return; } JDBCDriverBundleInfo info = infos.get(selected - 1); long bundleId = bundleManager.installBundle(new ProgressMonitorImpl(context), info.groupId, info.artifactId, info.version); context.println("bundle [" + bundleId + "] loaded"); } catch (InterruptedException e) { context.println(""); context.println("interrupted"); } catch (MavenResolveException e) { context.println("install failed"); } } private List<JDBCDriverBundleInfo> getDriverInfos() { List<JDBCDriverBundleInfo> infos = new ArrayList<JDBCDriverBundleInfo>(); infos.add(new JDBCDriverBundleInfo("MySQL", "com.mysql.jdbc", "com.springsource.com.mysql.jdbc", "5.1.6")); infos.add(new JDBCDriverBundleInfo("PostgreSQL", "org.postgresql", "com.springsource.org.postgresql.jdbc4", "8.3.604")); return infos; } /** * Create and register new entity manager factory with specified JPA model * bundle id and properties for overriding * * @param args * model bundle id and alias for entity manager factory */ @ScriptUsage(description = "Create and register new entity manager factory", arguments = { @ScriptArgument(name = "Bundle ID", type = "int", description = "Bundle that contains JPA model classes and kraken-jpa configurations"), @ScriptArgument(name = "Entity Manager Factory Name", type = "string", description = "Alias for entity manager factory") }) public void register(String[] args) { int bundleId = Integer.parseInt(args[0]); String factoryName = args[1]; Properties props = new Properties(); try { jpa.registerEntityManagerFactory(factoryName, props, bundleId); context.println(factoryName + " registered."); } catch (BundleException e) { context.println(e.getMessage()); } catch (PersistenceException e) { context.println(e.getMessage()); } catch (Exception e) { context.println(e.toString()); } } /** * Unregister and close the entity manager factory in JPA service * * @param args * empty array */ @ScriptUsage(description = "Close and unregister the entity manager", arguments = { @ScriptArgument(name = "Entity Manager Factory Name", type = "string", description = "Alias for entity manager factory") }) public void unregister(String[] args) { String factoryName = args[0]; if (!jpa.hasEntityManagerFactory(factoryName)) { context.println(factoryName + " not found"); return; } jpa.unregisterEntityManagerFactory(factoryName); context.println(factoryName + " unregistered."); } private static class DatabaseConfigTemplate { private String displayText; private String connectionString; private String driverClass; private String dialectClass; public DatabaseConfigTemplate(String displayText, String driverClass, String dialectClass, String connectionString) { this.displayText = displayText; this.driverClass = driverClass; this.connectionString = connectionString; this.dialectClass = dialectClass; } public void set(Properties props, String host, String db, String user, String password) { String url = connectionString.replace("$host", host).replace("$db", db); host = emptyToNull(host); db = emptyToNull(db); user = emptyToNull(user); password = emptyToNull(password); props.put("hibernate.dialect", dialectClass); props.put("hibernate.connection.driver_class", driverClass); props.put("hibernate.connection.url", url); if (user != null) props.put("hibernate.connection.username", user); if (password != null) props.put("hibernate.connection.password", password); } private String emptyToNull(String s) { if (s == null || s.isEmpty()) return null; return s; } @Override public String toString() { return displayText; } } private static class JDBCDriverBundleInfo { private String displayText; private String groupId; private String artifactId; private String version; private JDBCDriverBundleInfo(String displayText, String groupId, String artifactId, String version) { this.displayText = displayText; this.groupId = groupId; this.artifactId = artifactId; this.version = version; } @Override public String toString() { return displayText; } } private static class ProgressMonitorImpl implements ProgressMonitor { private ScriptContext context; public ProgressMonitorImpl(ScriptContext context) { this.context = context; } @Override public void write(String message) { context.print(message); } @Override public void writeln(String message) { context.println(message); } } }