/** * Copyright 2010 JBoss Inc * * 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.drools.guvnor.server.repository; /* * Copyright 2005 JBoss Inc * * 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. */ import java.math.BigInteger; import java.util.HashMap; import java.util.Map; import java.util.Properties; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import javax.jcr.LoginException; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; import org.drools.repository.*; import org.drools.repository.events.StorageEventManager; import org.drools.repository.events.CheckinEvent; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Create; import org.jboss.seam.annotations.Destroy; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.Startup; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This startup class manages the JCR repository, sets it up if necessary. * @author Michael Neale */ @Scope(ScopeType.APPLICATION) @Startup @Name("repositoryConfiguration") public class RepositoryStartupService { private static final Logger log = LoggerFactory.getLogger(RepositoryStartupService.class); private static final String ADMIN = "admin"; private static final String ADMIN_USER_PROPERTY = "org.drools.repository.admin.username"; private static final String ADMIN_PASSWORD_PROPERTY = "org.drools.repository.admin.password"; private static final String MAILMAN = "mailman"; private static final String MAILMAN_USER_PROPERTY = "org.drools.repository.mailman.username"; private static final String MAILMAN_PASSWORD_PROPERTY = "org.drools.repository.mailman.password"; private static final String SECURE_PASSWORDS_PROPERTY = "org.drools.repository.secure.passwords"; private RulesRepositoryConfigurator configurator; Map<String,String> properties = new HashMap<String,String>(); Repository repository; private Session sessionForSetup; private RulesRepository mailmanSession; public Repository getRepositoryInstance() { try { Properties properties = new Properties(); properties.putAll(this.properties); configurator = RulesRepositoryConfigurator.getInstance(properties); repository = configurator.getJCRRepository(); } catch (RepositoryException e) { log.error(e.getMessage(),e); } return repository; } @Create public void create() { repository = getRepositoryInstance(); String username = ADMIN; if (properties.containsKey(ADMIN_USER_PROPERTY)) { username = properties.get(ADMIN_USER_PROPERTY); } String password = "password"; if (properties.containsKey(ADMIN_PASSWORD_PROPERTY)) { password = properties.get(ADMIN_PASSWORD_PROPERTY); if ("true".equalsIgnoreCase(properties.get(SECURE_PASSWORDS_PROPERTY))) { password = decode(password); } } else { log.debug("Could not find property " + ADMIN_PASSWORD_PROPERTY + " for user " + ADMIN); } sessionForSetup = newSession(username,password); create( sessionForSetup ); startMailboxService(); registerCheckinListener(); } /** Listen for changes to the repository - for inbox purposes */ public static void registerCheckinListener() { System.out.println("Registering check-in listener"); StorageEventManager.registerCheckinEvent(new CheckinEvent() { public void afterCheckin(AssetItem item) { UserInbox.recordUserEditEvent(item); //to register that she edited... MailboxService.getInstance().recordItemUpdated(item); //for outgoing... MailboxService.getInstance().wakeUp(); } }); System.out.println("Check-in listener up"); } /** Start up the mailbox, flush out any messages that were left */ private void startMailboxService() { String username = MAILMAN; if (properties.containsKey(MAILMAN_USER_PROPERTY)) { username = properties.get(MAILMAN_USER_PROPERTY); } String password = "password"; if (properties.containsKey(MAILMAN_PASSWORD_PROPERTY)) { password = properties.get(MAILMAN_PASSWORD_PROPERTY); if ("true".equalsIgnoreCase(properties.get(SECURE_PASSWORDS_PROPERTY))) { password = decode(password); } } else { log.debug("Could not find property " + MAILMAN_PASSWORD_PROPERTY + " for user " + MAILMAN); } mailmanSession = new RulesRepository(newSession(username, password)); MailboxService.getInstance().init(mailmanSession); MailboxService.getInstance().wakeUp(); } void create(Session sessionForSetup) { RulesRepositoryAdministrator admin = new RulesRepositoryAdministrator(sessionForSetup); if (!admin.isRepositoryInitialized()) { try { configurator.setupRepository( sessionForSetup ); } catch (RepositoryException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // //Migrate v4 ruleflows to v5 //This section checks if the repository contains drools v4 //ruleflows that need to be migrated to drools v5 // RulesRepository repo = new RulesRepository(sessionForSetup); try { if ( MigrateRepository.needsRuleflowMigration(repo) ) { MigrateRepository.migrateRuleflows( repo ); } } catch ( RepositoryException e ) { e.printStackTrace(); throw new RulesRepositoryException(e); } } @Destroy public void close() { sessionForSetup.logout(); MailboxService.getInstance().stop(); mailmanSession.logout(); } public void setHomeDirectory(String home) { if (home!=null) { properties.put(JCRRepositoryConfigurator.REPOSITORY_ROOT_DIRECTORY, home); } } public void setRepositoryConfigurator(String clazz) throws ClassNotFoundException, InstantiationException, IllegalAccessException { if (clazz!=null) { properties.put(RulesRepositoryConfigurator.CONFIGURATOR_CLASS, clazz); } } /** * This will create a new Session, based on the current user. * @return */ public Session newSession(String userName) { try { return configurator.login(userName); } catch ( LoginException e ) { throw new RulesRepositoryException( "Unable to login to JCR backend." ); } catch ( RepositoryException e ) { throw new RulesRepositoryException( e ); } } /** * This will create a new Session, based on the current user. * @return */ public Session newSession(String userName, String password) { try { return configurator.login(userName, password); } catch ( LoginException e ) { throw new RulesRepositoryException("UserName: [ " + userName + "] Unable to login to JCR backend." ,e); } catch ( RepositoryException e ) { throw new RulesRepositoryException( e ); } } private static String decode(String secret) { String decodedPassword = secret; try { byte[] kbytes = "jaas is the way".getBytes(); SecretKeySpec key = new SecretKeySpec(kbytes, "Blowfish"); BigInteger n = new BigInteger(secret, 16); byte[] encoding = n.toByteArray(); //SECURITY-344: fix leading zeros if (encoding.length % 8 != 0) { int length = encoding.length; int newLength = ((length / 8) + 1) * 8; int pad = newLength - length; //number of leading zeros byte[] old = encoding; encoding = new byte[newLength]; for (int i = old.length - 1; i >= 0; i--) { encoding[i + pad] = old[i]; } } Cipher cipher = Cipher.getInstance("Blowfish"); cipher.init(Cipher.DECRYPT_MODE, key); byte[] decode = cipher.doFinal(encoding); decodedPassword = new String(decode); } catch (Exception e) { log.error(e.getMessage(),e); } return decodedPassword; } }