You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ah...@apache.org on 2013/07/27 00:01:59 UTC
[10/10] git commit: updated refs/heads/master to f5e5b39
Moved the DB layer code into framework-db and change only the necessary projects to refer to it. Cut down on the dependencies introduced with all the code in utils.
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/f5e5b39c
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/f5e5b39c
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/f5e5b39c
Branch: refs/heads/master
Commit: f5e5b39c9bc8d0e719dbb27cb8228b868c6f726f
Parents: 81b121b
Author: Alex Huang <al...@citrix.com>
Authored: Fri Jul 26 15:01:58 2013 -0700
Committer: Alex Huang <al...@citrix.com>
Committed: Fri Jul 26 15:02:10 2013 -0700
----------------------------------------------------------------------
api/pom.xml | 21 +-
.../api/response/ServiceOfferingResponse.java | 5 +-
api/src/org/apache/cloudstack/usage/Usage.java | 13 +-
.../cloudstack/test/utils/SpringUtils.java | 113 ++
awsapi/pom.xml | 5 +
engine/api/pom.xml | 5 +
engine/schema/pom.xml | 5 +
engine/storage/integration-test/pom.xml | 2 +-
framework/cluster/pom.xml | 5 +
framework/db/pom.xml | 24 +
.../db/src/com/cloud/dao/EntityManagerImpl.java | 125 ++
.../utils/crypt/EncryptionSecretKeyChanger.java | 427 ++++
.../db/src/com/cloud/utils/db/Attribute.java | 253 +++
.../com/cloud/utils/db/ConnectionConcierge.java | 223 +++
.../utils/db/ConnectionConciergeMBean.java | 30 +
framework/db/src/com/cloud/utils/db/DB.java | 59 +
framework/db/src/com/cloud/utils/db/DbUtil.java | 342 ++++
framework/db/src/com/cloud/utils/db/EcInfo.java | 106 +
.../db/src/com/cloud/utils/db/Encrypt.java | 32 +
framework/db/src/com/cloud/utils/db/Filter.java | 115 ++
.../db/src/com/cloud/utils/db/GenericDao.java | 284 +++
.../src/com/cloud/utils/db/GenericDaoBase.java | 1890 ++++++++++++++++++
.../cloud/utils/db/GenericSearchBuilder.java | 548 +++++
.../db/src/com/cloud/utils/db/GlobalLock.java | 244 +++
.../db/src/com/cloud/utils/db/GroupBy.java | 108 +
.../db/src/com/cloud/utils/db/JoinBuilder.java | 79 +
.../db/src/com/cloud/utils/db/JoinType.java | 32 +
.../db/src/com/cloud/utils/db/Merovingian2.java | 461 +++++
.../com/cloud/utils/db/MerovingianMBean.java | 32 +
.../db/src/com/cloud/utils/db/ScriptRunner.java | 233 +++
.../src/com/cloud/utils/db/SearchBuilder.java | 64 +
.../src/com/cloud/utils/db/SearchCriteria.java | 364 ++++
.../src/com/cloud/utils/db/SearchCriteria2.java | 213 ++
.../cloud/utils/db/SearchCriteriaService.java | 29 +
.../src/com/cloud/utils/db/SequenceFetcher.java | 171 ++
.../db/src/com/cloud/utils/db/SqlGenerator.java | 669 +++++++
.../db/src/com/cloud/utils/db/StateMachine.java | 30 +
.../db/src/com/cloud/utils/db/Transaction.java | 1174 +++++++++++
.../cloud/utils/db/TransactionAttachment.java | 34 +
.../utils/db/TransactionContextBuilder.java | 65 +
.../com/cloud/utils/db/TransactionMBean.java | 33 +
.../cloud/utils/db/TransactionMBeanImpl.java | 113 ++
.../src/com/cloud/utils/db/UpdateBuilder.java | 147 ++
.../db/src/com/cloud/utils/db/UpdateFilter.java | 29 +
.../com/cloud/utils/db/DbAnnotatedBase.java | 44 +
.../cloud/utils/db/DbAnnotatedBaseDerived.java | 27 +
.../db/test/com/cloud/utils/db/DbTestDao.java | 66 +
.../db/test/com/cloud/utils/db/DbTestUtils.java | 90 +
.../db/test/com/cloud/utils/db/DbTestVO.java | 56 +
.../test/com/cloud/utils/db/DummyComponent.java | 27 +
.../cloud/utils/db/ElementCollectionTest.java | 72 +
.../test/com/cloud/utils/db/GlobalLockTest.java | 81 +
.../com/cloud/utils/db/Merovingian2Test.java | 77 +
.../utils/db/TransactionContextBuilderTest.java | 63 +
.../com/cloud/utils/db/TransactionTest.java | 214 ++
plugins/hypervisors/vmware/pom.xml | 10 -
plugins/pom.xml | 2 +-
server/pom.xml | 2 +-
server/src/com/cloud/api/ApiDispatcher.java | 2 +-
server/src/com/cloud/api/ApiResponseHelper.java | 74 +-
server/src/com/cloud/dao/EntityManagerImpl.java | 150 --
usage/pom.xml | 2 +-
utils/pom.xml | 5 -
utils/src/com/cloud/utils/AnnotationHelper.java | 57 -
.../utils/crypt/EncryptionSecretKeyChanger.java | 427 ----
utils/src/com/cloud/utils/db/Attribute.java | 253 ---
.../com/cloud/utils/db/ConnectionConcierge.java | 223 ---
.../utils/db/ConnectionConciergeMBean.java | 30 -
utils/src/com/cloud/utils/db/DB.java | 59 -
utils/src/com/cloud/utils/db/DbUtil.java | 342 ----
utils/src/com/cloud/utils/db/EcInfo.java | 106 -
utils/src/com/cloud/utils/db/Encrypt.java | 32 -
utils/src/com/cloud/utils/db/EntityManager.java | 33 -
utils/src/com/cloud/utils/db/Filter.java | 115 --
utils/src/com/cloud/utils/db/GenericDao.java | 284 ---
.../src/com/cloud/utils/db/GenericDaoBase.java | 1890 ------------------
.../cloud/utils/db/GenericSearchBuilder.java | 548 -----
utils/src/com/cloud/utils/db/GlobalLock.java | 244 ---
utils/src/com/cloud/utils/db/GroupBy.java | 108 -
utils/src/com/cloud/utils/db/JoinBuilder.java | 79 -
utils/src/com/cloud/utils/db/JoinType.java | 32 -
utils/src/com/cloud/utils/db/Merovingian2.java | 461 -----
.../com/cloud/utils/db/MerovingianMBean.java | 32 -
utils/src/com/cloud/utils/db/ScriptRunner.java | 233 ---
utils/src/com/cloud/utils/db/SearchBuilder.java | 64 -
.../src/com/cloud/utils/db/SearchCriteria.java | 364 ----
.../src/com/cloud/utils/db/SearchCriteria2.java | 213 --
.../cloud/utils/db/SearchCriteriaService.java | 29 -
.../src/com/cloud/utils/db/SequenceFetcher.java | 171 --
utils/src/com/cloud/utils/db/SqlGenerator.java | 669 -------
utils/src/com/cloud/utils/db/StateMachine.java | 30 -
utils/src/com/cloud/utils/db/Transaction.java | 1174 -----------
.../cloud/utils/db/TransactionAttachment.java | 34 -
.../utils/db/TransactionContextBuilder.java | 65 -
.../com/cloud/utils/db/TransactionMBean.java | 33 -
.../cloud/utils/db/TransactionMBeanImpl.java | 113 --
utils/src/com/cloud/utils/db/UpdateBuilder.java | 147 --
utils/src/com/cloud/utils/db/UpdateFilter.java | 29 -
.../com/cloud/utils/db/DbAnnotatedBase.java | 44 -
.../cloud/utils/db/DbAnnotatedBaseDerived.java | 27 -
utils/test/com/cloud/utils/db/DbTestDao.java | 66 -
utils/test/com/cloud/utils/db/DbTestUtils.java | 90 -
utils/test/com/cloud/utils/db/DbTestVO.java | 56 -
.../test/com/cloud/utils/db/DummyComponent.java | 27 -
.../cloud/utils/db/ElementCollectionTest.java | 72 -
.../test/com/cloud/utils/db/GlobalLockTest.java | 83 -
.../com/cloud/utils/db/Merovingian2Test.java | 77 -
.../utils/db/TransactionContextBuilderTest.java | 63 -
.../com/cloud/utils/db/TransactionTest.java | 214 --
.../utils/log/CglibThrowableRendererTest.java | 104 -
.../cloudstack/test/utils/SpringUtils.java | 113 --
vmware-base/pom.xml | 5 +
.../vmware/mo/HypervisorHostHelper.java | 81 +-
113 files changed, 9842 insertions(+), 10023 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/api/pom.xml
----------------------------------------------------------------------
diff --git a/api/pom.xml b/api/pom.xml
index 8ca258f..3867e71 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -36,10 +36,27 @@
<artifactId>gson</artifactId>
<version>${cs.gson.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-framework-db</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<defaultGoal>install</defaultGoal>
- <sourceDirectory>src</sourceDirectory>
- <testSourceDirectory>test</testSourceDirectory>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
</build>
</project>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/api/src/org/apache/cloudstack/api/response/ServiceOfferingResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/ServiceOfferingResponse.java b/api/src/org/apache/cloudstack/api/response/ServiceOfferingResponse.java
index 288f76b..41a9b79 100644
--- a/api/src/org/apache/cloudstack/api/response/ServiceOfferingResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/ServiceOfferingResponse.java
@@ -18,7 +18,7 @@ package org.apache.cloudstack.api.response;
import java.util.Date;
-import javax.persistence.Column;
+import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
@@ -26,7 +26,6 @@ import org.apache.cloudstack.api.EntityReference;
import com.cloud.offering.ServiceOffering;
import com.cloud.serializer.Param;
-import com.google.gson.annotations.SerializedName;
@EntityReference(value = ServiceOffering.class)
public class ServiceOfferingResponse extends BaseResponse {
@@ -141,7 +140,7 @@ public class ServiceOfferingResponse extends BaseResponse {
}
public void setSystemVmType(String vmtype) {
- this.vm_type = vmtype;
+ vm_type = vmtype;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/api/src/org/apache/cloudstack/usage/Usage.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/usage/Usage.java b/api/src/org/apache/cloudstack/usage/Usage.java
index 23f9d42..1bb1e90 100644
--- a/api/src/org/apache/cloudstack/usage/Usage.java
+++ b/api/src/org/apache/cloudstack/usage/Usage.java
@@ -16,19 +16,8 @@
// under the License.
package org.apache.cloudstack.usage;
-import org.apache.cloudstack.api.InternalIdentity;
-
import java.util.Date;
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.Table;
-import javax.persistence.Temporal;
-import javax.persistence.TemporalType;
-
public interface Usage {
public long getId();
@@ -39,7 +28,7 @@ public interface Usage {
public Long getDomainId();
- public String getDescription();
+ public String getDescription();
public String getUsageDisplay();
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/api/test/org/apache/cloudstack/test/utils/SpringUtils.java
----------------------------------------------------------------------
diff --git a/api/test/org/apache/cloudstack/test/utils/SpringUtils.java b/api/test/org/apache/cloudstack/test/utils/SpringUtils.java
new file mode 100644
index 0000000..220bd80
--- /dev/null
+++ b/api/test/org/apache/cloudstack/test/utils/SpringUtils.java
@@ -0,0 +1,113 @@
+// 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
+// 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.apache.cloudstack.test.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+
+import com.cloud.utils.component.ComponentContext;
+import com.cloud.utils.component.ComponentInstantiationPostProcessor;
+import com.cloud.utils.component.ComponentMethodInterceptor;
+import com.cloud.utils.db.TransactionContextBuilder;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+public class SpringUtils {
+
+ /**
+ * This method allows you to use @ComponentScan for your unit testing but
+ * it limits the scope of the classes found to the class specified in
+ * the @ComponentScan annotation.
+ *
+ * Without using this method, the default behavior of @ComponentScan is
+ * to actually scan in the package of the class specified rather than
+ * only the class. This can cause extra classes to be loaded which causes
+ * the classes these extra classes depend on to be loaded. The end effect
+ * is often most of the project gets loaded.
+ *
+ * In order to use this method properly, you must do the following: <li>
+ * - Specify @ComponentScan with basePackageClasses, includeFilters, and
+ * useDefaultFilters=true. See the following example.
+ *
+ * <pre>
+ * @ComponentScan(basePackageClasses={AffinityGroupServiceImpl.class, EventUtils.class},
+ * includeFilters={@Filter(value=TestConfiguration.Library.class, type=FilterType.CUSTOM)},
+ * useDefaultFilters=false)
+ * </pre>
+ *
+ * - Create a Library class and use that to call this method. See the
+ * following example. The Library class you define here is the Library
+ * class being added in the filter above.
+ *
+ * <pre>
+ * public static class Library implements TypeFilter {
+ * @Override
+ * public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException {
+ * ComponentScan cs = TestConfiguration.class.getAnnotation(ComponentScan.class);
+ * return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs);
+ * }
+ * }
+ * </pre>
+ *
+ * @param clazzName name of the class that should be included in the Spring components
+ * @param cs ComponentScan annotation that was declared on the configuration
+ *
+ * @return
+ */
+ public static boolean includedInBasePackageClasses(String clazzName, ComponentScan cs) {
+ Class<?> clazzToCheck;
+ try {
+ clazzToCheck = Class.forName(clazzName);
+ } catch (ClassNotFoundException e) {
+ throw new CloudRuntimeException("Unable to find " + clazzName);
+ }
+ Class<?>[] clazzes = cs.basePackageClasses();
+ for (Class<?> clazz : clazzes) {
+ if (clazzToCheck.isAssignableFrom(clazz)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static class CloudStackTestConfiguration {
+
+ @Bean
+ public ComponentContext componentContext() {
+ return new ComponentContext();
+ }
+
+ @Bean
+ public TransactionContextBuilder transactionContextBuilder() {
+ return new TransactionContextBuilder();
+ }
+
+ @Bean
+ public ComponentInstantiationPostProcessor instantiatePostProcessor() {
+ ComponentInstantiationPostProcessor processor = new ComponentInstantiationPostProcessor();
+
+ List<ComponentMethodInterceptor> interceptors = new ArrayList<ComponentMethodInterceptor>();
+ interceptors.add(new TransactionContextBuilder());
+ processor.setInterceptors(interceptors);
+
+ return processor;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/awsapi/pom.xml
----------------------------------------------------------------------
diff --git a/awsapi/pom.xml b/awsapi/pom.xml
index 2fe2089..317d1ce 100644
--- a/awsapi/pom.xml
+++ b/awsapi/pom.xml
@@ -289,6 +289,11 @@
<artifactId>javassist</artifactId>
<version>3.9.0.GA</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-framework-db</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
<build>
<resources>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/engine/api/pom.xml
----------------------------------------------------------------------
diff --git a/engine/api/pom.xml b/engine/api/pom.xml
index 1b8f26c..ccea255 100644
--- a/engine/api/pom.xml
+++ b/engine/api/pom.xml
@@ -27,6 +27,11 @@
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-framework-db</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-api</artifactId>
<version>${project.version}</version>
</dependency>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/engine/schema/pom.xml
----------------------------------------------------------------------
diff --git a/engine/schema/pom.xml b/engine/schema/pom.xml
index da40d9c..a9ad13f 100644
--- a/engine/schema/pom.xml
+++ b/engine/schema/pom.xml
@@ -43,6 +43,11 @@
<artifactId>cloud-engine-components-api</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-framework-db</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
<build>
<defaultGoal>install</defaultGoal>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/engine/storage/integration-test/pom.xml
----------------------------------------------------------------------
diff --git a/engine/storage/integration-test/pom.xml b/engine/storage/integration-test/pom.xml
index 4df4451..d082710 100644
--- a/engine/storage/integration-test/pom.xml
+++ b/engine/storage/integration-test/pom.xml
@@ -64,7 +64,7 @@
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
- <artifactId>cloud-utils</artifactId>
+ <artifactId>cloud-api</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/framework/cluster/pom.xml
----------------------------------------------------------------------
diff --git a/framework/cluster/pom.xml b/framework/cluster/pom.xml
index 116b635..131511d 100644
--- a/framework/cluster/pom.xml
+++ b/framework/cluster/pom.xml
@@ -24,5 +24,10 @@
<artifactId>cloud-utils</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-framework-db</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
</project>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/framework/db/pom.xml
----------------------------------------------------------------------
diff --git a/framework/db/pom.xml b/framework/db/pom.xml
index b4011c7..c23f96f 100644
--- a/framework/db/pom.xml
+++ b/framework/db/pom.xml
@@ -20,9 +20,33 @@
</parent>
<dependencies>
<dependency>
+ <groupId>javax.ejb</groupId>
+ <artifactId>ejb-api</artifactId>
+ <version>${cs.ejb.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.persistence</groupId>
+ <artifactId>javax.persistence</artifactId>
+ <version>${cs.jpa.version}</version>
+ </dependency>
+ <dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-utils</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>com/cloud/utils/testcase/*TestCase*</exclude>
+ <exclude>com/cloud/utils/db/*Test*</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
</project>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/framework/db/src/com/cloud/dao/EntityManagerImpl.java
----------------------------------------------------------------------
diff --git a/framework/db/src/com/cloud/dao/EntityManagerImpl.java b/framework/db/src/com/cloud/dao/EntityManagerImpl.java
new file mode 100644
index 0000000..bb493c0
--- /dev/null
+++ b/framework/db/src/com/cloud/dao/EntityManagerImpl.java
@@ -0,0 +1,125 @@
+// 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 com.cloud.dao;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+
+import net.sf.ehcache.Cache;
+
+import com.cloud.utils.component.ManagerBase;
+import com.cloud.utils.db.EntityManager;
+import com.cloud.utils.db.GenericDao;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.GenericSearchBuilder;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+
+@Local(value=EntityManager.class)
+@SuppressWarnings("unchecked")
+public class EntityManagerImpl extends ManagerBase implements EntityManager {
+ String _name;
+ Cache _cache;
+
+ @Override
+ public <T, K extends Serializable> T findById(Class<T> entityType, K id) {
+ GenericDao<? extends T, K> dao = (GenericDao<? extends T, K>)GenericDaoBase.getDao(entityType);
+ return dao.findById(id);
+ }
+
+ public <T, K extends Serializable> T findByIdIncludingRemoved(Class<T> entityType, K id) {
+ GenericDao<? extends T, K> dao = (GenericDao<? extends T, K>)GenericDaoBase.getDao(entityType);
+ return dao.findByIdIncludingRemoved(id);
+ }
+
+ @Override
+ public <T> T findByUuid(Class<T> entityType, String uuid) {
+ // Finds and returns a unique VO using uuid, null if entity not found in db
+ GenericDao<? extends T, String> dao = (GenericDao<? extends T, String>)GenericDaoBase.getDao(entityType);
+ return dao.findByUuid(uuid);
+ }
+
+ public <T> T findByUuidIncludingRemoved(Class<T> entityType, String uuid) {
+ // Finds and returns a unique VO using uuid, null if entity not found in db
+ GenericDao<? extends T, String> dao = (GenericDao<? extends T, String>)GenericDaoBase.getDao(entityType);
+ return dao.findByUuidIncludingRemoved(uuid);
+ }
+
+ @Override
+ public <T> T findByXId(Class<T> entityType, String xid) {
+ return null;
+ }
+
+ @Override
+ public <T> List<? extends T> list(Class<T> entityType) {
+ GenericDao<? extends T, ? extends Serializable> dao = GenericDaoBase.getDao(entityType);
+ return dao.listAll();
+ }
+
+ public <T> T persist(T t) {
+ GenericDao<T, ? extends Serializable> dao = (GenericDao<T, ? extends Serializable>)GenericDaoBase.getDao((Class<T>)t.getClass());
+ return dao.persist(t);
+ }
+
+ public <T> SearchBuilder<T> createSearchBuilder(Class<T> entityType) {
+ GenericDao<T, ? extends Serializable> dao = (GenericDao<T, ? extends Serializable>)GenericDaoBase.getDao(entityType);
+ return dao.createSearchBuilder();
+ }
+
+ public <T, K> GenericSearchBuilder<T, K> createGenericSearchBuilder(Class<T> entityType, Class<K> resultType) {
+ GenericDao<T, ? extends Serializable> dao = (GenericDao<T, ? extends Serializable>)GenericDaoBase.getDao(entityType);
+ return dao.createSearchBuilder((Class<K>)resultType.getClass());
+ }
+
+ @Override
+ public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+ _name = name;
+
+ return true;
+ }
+
+ @Override
+ public boolean start() {
+ return true;
+ }
+
+ @Override
+ public boolean stop() {
+ return true;
+ }
+
+ @Override
+ public String getName() {
+ return _name;
+ }
+
+ public <T, K> List<K> search(Class<T> entityType, SearchCriteria<K> sc) {
+ GenericDao<T, ? extends Serializable> dao = (GenericDao<T, ? extends Serializable>)GenericDaoBase.getDao(entityType);
+ return dao.customSearch(sc, null);
+ }
+
+ @Override
+ public <T, K extends Serializable> void remove(Class<T> entityType, K id) {
+ GenericDao<T, K> dao = (GenericDao<T, K>)GenericDaoBase.getDao(entityType);
+ dao.remove(id);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/framework/db/src/com/cloud/utils/crypt/EncryptionSecretKeyChanger.java
----------------------------------------------------------------------
diff --git a/framework/db/src/com/cloud/utils/crypt/EncryptionSecretKeyChanger.java b/framework/db/src/com/cloud/utils/crypt/EncryptionSecretKeyChanger.java
new file mode 100755
index 0000000..9b13eb8
--- /dev/null
+++ b/framework/db/src/com/cloud/utils/crypt/EncryptionSecretKeyChanger.java
@@ -0,0 +1,427 @@
+// 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
+// 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 com.cloud.utils.crypt;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+
+import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
+import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
+import org.jasypt.exceptions.EncryptionOperationNotPossibleException;
+import org.jasypt.properties.EncryptableProperties;
+
+import com.cloud.utils.PropertiesUtil;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+
+/*
+ * EncryptionSecretKeyChanger updates Management Secret Key / DB Secret Key or both.
+ * DB secret key is validated against the key in db.properties
+ * db.properties is updated with values encrypted using new MS secret key
+ * DB data migrated using new DB secret key
+ */
+public class EncryptionSecretKeyChanger {
+
+ private StandardPBEStringEncryptor oldEncryptor = new StandardPBEStringEncryptor();
+ private StandardPBEStringEncryptor newEncryptor = new StandardPBEStringEncryptor();
+ private static final String keyFile = "/etc/cloudstack/management/key";
+
+ public static void main(String[] args){
+ List<String> argsList = Arrays.asList(args);
+ Iterator<String> iter = argsList.iterator();
+ String oldMSKey = null;
+ String oldDBKey = null;
+ String newMSKey = null;
+ String newDBKey = null;
+
+ //Parse command-line args
+ while (iter.hasNext()) {
+ String arg = iter.next();
+ // Old MS Key
+ if (arg.equals("-m")) {
+ oldMSKey = iter.next();
+ }
+ // Old DB Key
+ if (arg.equals("-d")) {
+ oldDBKey = iter.next();
+ }
+ // New MS Key
+ if (arg.equals("-n")) {
+ newMSKey = iter.next();
+ }
+ // New DB Key
+ if (arg.equals("-e")) {
+ newDBKey = iter.next();
+ }
+ }
+
+ if(oldMSKey == null || oldDBKey ==null){
+ System.out.println("Existing MS secret key or DB secret key is not provided");
+ usage();
+ return;
+ }
+
+ if(newMSKey == null && newDBKey ==null){
+ System.out.println("New MS secret key and DB secret are both not provided");
+ usage();
+ return;
+ }
+
+ final File dbPropsFile = PropertiesUtil.findConfigFile("db.properties");
+ final Properties dbProps;
+ EncryptionSecretKeyChanger keyChanger = new EncryptionSecretKeyChanger();
+ StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
+ keyChanger.initEncryptor(encryptor, oldMSKey);
+ dbProps = new EncryptableProperties(encryptor);
+ PropertiesConfiguration backupDBProps = null;
+
+ System.out.println("Parsing db.properties file");
+ try {
+ dbProps.load(new FileInputStream(dbPropsFile));
+ backupDBProps = new PropertiesConfiguration(dbPropsFile);
+ } catch (FileNotFoundException e) {
+ System.out.println("db.properties file not found while reading DB secret key" +e.getMessage());
+ } catch (IOException e) {
+ System.out.println("Error while reading DB secret key from db.properties" +e.getMessage());
+ } catch (ConfigurationException e) {
+ e.printStackTrace();
+ }
+
+ String dbSecretKey = null;
+ try {
+ dbSecretKey = dbProps.getProperty("db.cloud.encrypt.secret");
+ } catch (EncryptionOperationNotPossibleException e) {
+ System.out.println("Failed to decrypt existing DB secret key from db.properties. "+e.getMessage());
+ return;
+ }
+
+ if(!oldDBKey.equals(dbSecretKey)){
+ System.out.println("Incorrect MS Secret Key or DB Secret Key");
+ return;
+ }
+
+ System.out.println("Secret key provided matched the key in db.properties");
+ final String encryptionType = dbProps.getProperty("db.cloud.encryption.type");
+
+ if(newMSKey == null){
+ System.out.println("No change in MS Key. Skipping migrating db.properties");
+ } else {
+ if(!keyChanger.migrateProperties(dbPropsFile, dbProps, newMSKey, newDBKey)){
+ System.out.println("Failed to update db.properties");
+ return;
+ } else {
+ //db.properties updated successfully
+ if(encryptionType.equals("file")){
+ //update key file with new MS key
+ try {
+ FileWriter fwriter = new FileWriter(keyFile);
+ BufferedWriter bwriter = new BufferedWriter(fwriter);
+ bwriter.write(newMSKey);
+ bwriter.close();
+ } catch (IOException e) {
+ System.out.println("Failed to write new secret to file. Please update the file manually");
+ }
+ }
+ }
+ }
+
+ boolean success = false;
+ if(newDBKey == null || newDBKey.equals(oldDBKey)){
+ System.out.println("No change in DB Secret Key. Skipping Data Migration");
+ } else {
+ EncryptionSecretKeyChecker.initEncryptorForMigration(oldMSKey);
+ try {
+ success = keyChanger.migrateData(oldDBKey, newDBKey);
+ } catch (Exception e) {
+ System.out.println("Error during data migration");
+ e.printStackTrace();
+ success = false;
+ }
+ }
+
+ if(success){
+ System.out.println("Successfully updated secret key(s)");
+ }
+ else {
+ System.out.println("Data Migration failed. Reverting db.properties");
+ //revert db.properties
+ try {
+ backupDBProps.save();
+ } catch (ConfigurationException e) {
+ e.printStackTrace();
+ }
+ if(encryptionType.equals("file")){
+ //revert secret key in file
+ try {
+ FileWriter fwriter = new FileWriter(keyFile);
+ BufferedWriter bwriter = new BufferedWriter(fwriter);
+ bwriter.write(oldMSKey);
+ bwriter.close();
+ } catch (IOException e) {
+ System.out.println("Failed to revert to old secret to file. Please update the file manually");
+ }
+ }
+ }
+ }
+
+ private boolean migrateProperties(File dbPropsFile, Properties dbProps, String newMSKey, String newDBKey){
+ System.out.println("Migrating db.properties..");
+ StandardPBEStringEncryptor msEncryptor = new StandardPBEStringEncryptor();;
+ initEncryptor(msEncryptor, newMSKey);
+
+ try {
+ PropertiesConfiguration newDBProps = new PropertiesConfiguration(dbPropsFile);
+ if(newDBKey!=null && !newDBKey.isEmpty()){
+ newDBProps.setProperty("db.cloud.encrypt.secret", "ENC("+msEncryptor.encrypt(newDBKey)+")");
+ }
+ String prop = dbProps.getProperty("db.cloud.password");
+ if(prop!=null && !prop.isEmpty()){
+ newDBProps.setProperty("db.cloud.password", "ENC("+msEncryptor.encrypt(prop)+")");
+ }
+ prop = dbProps.getProperty("db.usage.password");
+ if(prop!=null && !prop.isEmpty()){
+ newDBProps.setProperty("db.usage.password", "ENC("+msEncryptor.encrypt(prop)+")");
+ }
+ newDBProps.save(dbPropsFile.getAbsolutePath());
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ System.out.println("Migrating db.properties Done.");
+ return true;
+ }
+
+ private boolean migrateData(String oldDBKey, String newDBKey){
+ System.out.println("Begin Data migration");
+ initEncryptor(oldEncryptor, oldDBKey);
+ initEncryptor(newEncryptor, newDBKey);
+ System.out.println("Initialised Encryptors");
+
+ Transaction txn = Transaction.open("Migrate");
+ txn.start();
+ try {
+ Connection conn;
+ try {
+ conn = txn.getConnection();
+ } catch (SQLException e) {
+ throw new CloudRuntimeException("Unable to migrate encrypted data in the database", e);
+ }
+
+ migrateConfigValues(conn);
+ migrateHostDetails(conn);
+ migrateVNCPassword(conn);
+ migrateUserCredentials(conn);
+
+ txn.commit();
+ } finally {
+ txn.close();
+ }
+ System.out.println("End Data migration");
+ return true;
+ }
+
+ private void initEncryptor(StandardPBEStringEncryptor encryptor, String secretKey){
+ encryptor.setAlgorithm("PBEWithMD5AndDES");
+ SimpleStringPBEConfig stringConfig = new SimpleStringPBEConfig();
+ stringConfig.setPassword(secretKey);
+ encryptor.setConfig(stringConfig);
+ }
+
+ private String migrateValue(String value){
+ if(value ==null || value.isEmpty()){
+ return value;
+ }
+ String decryptVal = oldEncryptor.decrypt(value);
+ return newEncryptor.encrypt(decryptVal);
+ }
+
+ private void migrateConfigValues(Connection conn) {
+ System.out.println("Begin migrate config values");
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ pstmt = conn.prepareStatement("select name, value from configuration where category in ('Hidden', 'Secure')");
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ String name = rs.getString(1);
+ String value = rs.getString(2);
+ if(value == null || value.isEmpty()){
+ continue;
+ }
+ String encryptedValue = migrateValue(value);
+ pstmt = conn.prepareStatement("update configuration set value=? where name=?");
+ pstmt.setBytes(1, encryptedValue.getBytes("UTF-8"));
+ pstmt.setString(2, name);
+ pstmt.executeUpdate();
+ }
+ } catch (SQLException e) {
+ throw new CloudRuntimeException("Unable to update configuration values ", e);
+ } catch (UnsupportedEncodingException e) {
+ throw new CloudRuntimeException("Unable to update configuration values ", e);
+ } finally {
+ try {
+ if (rs != null) {
+ rs.close();
+ }
+
+ if (pstmt != null) {
+ pstmt.close();
+ }
+ } catch (SQLException e) {
+ }
+ }
+ System.out.println("End migrate config values");
+ }
+
+ private void migrateHostDetails(Connection conn) {
+ System.out.println("Begin migrate host details");
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ pstmt = conn.prepareStatement("select id, value from host_details where name = 'password'");
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ long id = rs.getLong(1);
+ String value = rs.getString(2);
+ if(value == null || value.isEmpty()){
+ continue;
+ }
+ String encryptedValue = migrateValue(value);
+ pstmt = conn.prepareStatement("update host_details set value=? where id=?");
+ pstmt.setBytes(1, encryptedValue.getBytes("UTF-8"));
+ pstmt.setLong(2, id);
+ pstmt.executeUpdate();
+ }
+ } catch (SQLException e) {
+ throw new CloudRuntimeException("Unable update host_details values ", e);
+ } catch (UnsupportedEncodingException e) {
+ throw new CloudRuntimeException("Unable update host_details values ", e);
+ } finally {
+ try {
+ if (rs != null) {
+ rs.close();
+ }
+
+ if (pstmt != null) {
+ pstmt.close();
+ }
+ } catch (SQLException e) {
+ }
+ }
+ System.out.println("End migrate host details");
+ }
+
+ private void migrateVNCPassword(Connection conn) {
+ System.out.println("Begin migrate VNC password");
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ pstmt = conn.prepareStatement("select id, vnc_password from vm_instance");
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ long id = rs.getLong(1);
+ String value = rs.getString(2);
+ if(value == null || value.isEmpty()){
+ continue;
+ }
+ String encryptedValue = migrateValue(value);
+ pstmt = conn.prepareStatement("update vm_instance set vnc_password=? where id=?");
+ pstmt.setBytes(1, encryptedValue.getBytes("UTF-8"));
+ pstmt.setLong(2, id);
+ pstmt.executeUpdate();
+ }
+ } catch (SQLException e) {
+ throw new CloudRuntimeException("Unable update vm_instance vnc_password ", e);
+ } catch (UnsupportedEncodingException e) {
+ throw new CloudRuntimeException("Unable update vm_instance vnc_password ", e);
+ } finally {
+ try {
+ if (rs != null) {
+ rs.close();
+ }
+
+ if (pstmt != null) {
+ pstmt.close();
+ }
+ } catch (SQLException e) {
+ }
+ }
+ System.out.println("End migrate VNC password");
+ }
+
+ private void migrateUserCredentials(Connection conn) {
+ System.out.println("Begin migrate user credentials");
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ pstmt = conn.prepareStatement("select id, secret_key from user");
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ long id = rs.getLong(1);
+ String secretKey = rs.getString(2);
+ if(secretKey == null || secretKey.isEmpty()){
+ continue;
+ }
+ String encryptedSecretKey = migrateValue(secretKey);
+ pstmt = conn.prepareStatement("update user set secret_key=? where id=?");
+ pstmt.setBytes(1, encryptedSecretKey.getBytes("UTF-8"));
+ pstmt.setLong(2, id);
+ pstmt.executeUpdate();
+ }
+ } catch (SQLException e) {
+ throw new CloudRuntimeException("Unable update user secret key ", e);
+ } catch (UnsupportedEncodingException e) {
+ throw new CloudRuntimeException("Unable update user secret key ", e);
+ } finally {
+ try {
+ if (rs != null) {
+ rs.close();
+ }
+
+ if (pstmt != null) {
+ pstmt.close();
+ }
+ } catch (SQLException e) {
+ }
+ }
+ System.out.println("End migrate user credentials");
+ }
+
+ private static void usage(){
+ System.out.println("Usage: \tEncryptionSecretKeyChanger \n" +
+ "\t\t-m <Mgmt Secret Key> \n" +
+ "\t\t-d <DB Secret Key> \n" +
+ "\t\t-n [New Mgmt Secret Key] \n" +
+ "\t\t-e [New DB Secret Key]");
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/framework/db/src/com/cloud/utils/db/Attribute.java
----------------------------------------------------------------------
diff --git a/framework/db/src/com/cloud/utils/db/Attribute.java b/framework/db/src/com/cloud/utils/db/Attribute.java
new file mode 100755
index 0000000..22fd969
--- /dev/null
+++ b/framework/db/src/com/cloud/utils/db/Attribute.java
@@ -0,0 +1,253 @@
+// 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
+// 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 com.cloud.utils.db;
+
+import java.lang.reflect.Field;
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+/**
+ * The Java annotation are somewhat incomplete. This gives better information
+ * about exactly what each field has.
+ *
+ */
+public class Attribute {
+ public enum Flag {
+ Insertable(0x01),
+ Updatable(0x02),
+ Nullable(0x04),
+ DaoGenerated(0x08),
+ DbGenerated(0x10),
+ Embedded(0x20),
+ Id(0x40),
+ Selectable(0x80),
+ Time(0x100),
+ Date(0x200),
+ TimeStamp(0x400),
+ SequenceGV(0x1000),
+ TableGV(0x2000),
+ AutoGV(0x4000),
+ Created(0x10000),
+ Removed(0x20000),
+ DC(0x40000),
+ CharDT(0x100000),
+ StringDT(0x200000),
+ IntegerDT(0x400000),
+ Encrypted(0x800000);
+
+ int place;
+ Flag(int place) {
+ this.place = place;
+ }
+
+ public int place() {
+ return place;
+ }
+
+ public boolean check(int value) {
+ return (value & place) == place;
+ }
+
+ public int setTrue(int value) {
+ return (value | place);
+ }
+
+ public int setFalse(int value) {
+ return (value & ~place);
+ }
+ }
+
+ protected String table;
+ protected String columnName;
+ protected Field field;
+ protected int flags;
+ protected Column column;
+ protected Object attache;
+
+ public Attribute(Class<?> clazz, AttributeOverride[] overrides, Field field, String tableName, boolean isEmbedded, boolean isId) {
+ this.field = field;
+ flags = 0;
+ table = tableName;
+ setupColumnInfo(clazz, overrides, tableName, isEmbedded, isId);
+ }
+
+ public Attribute(String table, String columnName) {
+ this.table = table;
+ this.columnName = columnName;
+ this.field = null;
+ this.column = null;
+ }
+
+ protected void setupColumnInfo(Class<?> clazz, AttributeOverride[] overrides, String tableName, boolean isEmbedded, boolean isId) {
+ flags = Flag.Selectable.setTrue(flags);
+ GeneratedValue gv = field.getAnnotation(GeneratedValue.class);
+ if (gv != null) {
+ if (gv.strategy() == GenerationType.IDENTITY) {
+ flags = Flag.DbGenerated.setTrue(flags);
+ } else if (gv.strategy() == GenerationType.SEQUENCE) {
+ assert (false) : "Sequence generation not supported.";
+ flags = Flag.DaoGenerated.setTrue(flags);
+ flags = Flag.Insertable.setTrue(flags);
+ flags = Flag.SequenceGV.setTrue(flags);
+ } else if (gv.strategy() == GenerationType.TABLE) {
+ flags = Flag.DaoGenerated.setTrue(flags);
+ flags = Flag.Insertable.setTrue(flags);
+ flags = Flag.TableGV.setTrue(flags);
+ } else if (gv.strategy() == GenerationType.AUTO) {
+ flags = Flag.DaoGenerated.setTrue(flags);
+ flags = Flag.Insertable.setTrue(flags);
+ flags = Flag.AutoGV.setTrue(flags);
+ }
+ }
+
+ if (isEmbedded) {
+ flags = Flag.Embedded.setTrue(flags);
+ }
+
+ if (isId) {
+ flags = Flag.Id.setTrue(flags);
+ } else {
+ Id id = field.getAnnotation(Id.class);
+ if (id != null) {
+ flags = Flag.Id.setTrue(flags);
+ }
+ }
+ column = field.getAnnotation(Column.class);
+ if (gv == null) {
+ if (column == null || (column.insertable() && column.table().length() == 0)) {
+ flags = Flag.Insertable.setTrue(flags);
+ }
+ if (column == null || (column.updatable() && column.table().length() == 0)) {
+ flags = Flag.Updatable.setTrue(flags);
+ }
+ if (column == null || column.nullable()) {
+ flags = Flag.Nullable.setTrue(flags);
+ }
+ Encrypt encrypt = field.getAnnotation(Encrypt.class);
+ if (encrypt != null && encrypt.encrypt()) {
+ flags = Flag.Encrypted.setTrue(flags);
+ }
+ }
+ ElementCollection ec = field.getAnnotation(ElementCollection.class);
+ if (ec != null) {
+ flags = Flag.Insertable.setFalse(flags);
+ flags = Flag.Selectable.setFalse(flags);
+ }
+
+ Temporal temporal = field.getAnnotation(Temporal.class);
+ if (temporal != null) {
+ if (temporal.value() == TemporalType.DATE) {
+ flags = Flag.Date.setTrue(flags);
+ } else if (temporal.value() == TemporalType.TIME) {
+ flags = Flag.Time.setTrue(flags);
+ } else if (temporal.value() == TemporalType.TIMESTAMP) {
+ flags = Flag.TimeStamp.setTrue(flags);
+ }
+ }
+
+ if (column != null && column.table().length() > 0) {
+ table = column.table();
+ }
+
+ columnName = DbUtil.getColumnName(field, overrides);
+ }
+
+ public final boolean isInsertable() {
+ return Flag.Insertable.check(flags);
+ }
+
+ public final boolean isUpdatable() {
+ return Flag.Updatable.check(flags);
+ }
+
+ public final boolean isNullable() {
+ return Flag.Nullable.check(flags);
+ }
+
+ public final boolean isId() {
+ return Flag.Id.check(flags);
+ }
+
+ public final boolean isSelectable() {
+ return Flag.Selectable.check(flags);
+ }
+
+ public final boolean is(Flag flag) {
+ return flag.check(flags);
+ }
+
+ public final void setTrue(Flag flag) {
+ flags = flag.setTrue(flags);
+ }
+
+ public final void setFalse(Flag flag) {
+ flags = flag.setFalse(flags);
+ }
+
+ public final boolean isEncrypted() {
+ return Flag.Encrypted.check(flags);
+ }
+
+ public Field getField() {
+ return field;
+ }
+
+ public Object get(Object entity) {
+ try {
+ return field.get(entity);
+ } catch (IllegalAccessException e) {
+ assert (false) : "How did we get here?";
+ return null;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return columnName.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Attribute)) {
+ return false;
+ }
+
+ Attribute that = (Attribute)obj;
+
+ return columnName.equals(that.columnName) && table.equals(that.table);
+ }
+
+ @Override
+ public String toString() {
+ return table + "." + columnName;
+ }
+
+ public String getColumnName() {
+ return columnName;
+ }
+
+ public void setColumnName(String columnName) {
+ this.columnName = columnName;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/framework/db/src/com/cloud/utils/db/ConnectionConcierge.java
----------------------------------------------------------------------
diff --git a/framework/db/src/com/cloud/utils/db/ConnectionConcierge.java b/framework/db/src/com/cloud/utils/db/ConnectionConcierge.java
new file mode 100644
index 0000000..0294334
--- /dev/null
+++ b/framework/db/src/com/cloud/utils/db/ConnectionConcierge.java
@@ -0,0 +1,223 @@
+// 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
+// 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 com.cloud.utils.db;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.management.StandardMBean;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.utils.concurrency.NamedThreadFactory;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.mgmt.JmxUtil;
+
+/**
+ * ConnectionConcierge keeps stand alone database connections alive. This is
+ * needs someone to keep that database connection from being garbage collected
+ *
+ */
+public class ConnectionConcierge {
+
+ static final Logger s_logger = Logger.getLogger(ConnectionConcierge.class);
+
+ static final ConnectionConciergeManager s_mgr = new ConnectionConciergeManager();
+
+ Connection _conn;
+ String _name;
+ boolean _keepAlive;
+ boolean _autoCommit;
+ int _isolationLevel;
+ int _holdability;
+
+ public ConnectionConcierge(String name, Connection conn, boolean keepAlive) {
+ _name = name + s_mgr.getNextId();
+ _keepAlive = keepAlive;
+ try {
+ _autoCommit = conn.getAutoCommit();
+ _isolationLevel = conn.getTransactionIsolation();
+ _holdability = conn.getHoldability();
+ } catch (SQLException e) {
+ throw new CloudRuntimeException("Unable to get information from the connection object", e);
+ }
+ reset(conn);
+ }
+
+ public void reset(Connection conn) {
+ try {
+ release();
+ } catch (Throwable th) {
+ s_logger.error("Unable to release a connection", th);
+ }
+ _conn = conn;
+ try {
+ _conn.setAutoCommit(_autoCommit);
+ _conn.setHoldability(_holdability);
+ _conn.setTransactionIsolation(_isolationLevel);
+ } catch (SQLException e) {
+ s_logger.error("Unable to release a connection", e);
+ }
+ s_mgr.register(_name, this);
+ s_logger.debug("Registering a database connection for " + _name);
+ }
+
+ public final Connection conn() {
+ return _conn;
+ }
+
+ public void release() {
+ s_mgr.unregister(_name);
+ try {
+ if (_conn != null) {
+ _conn.close();
+ }
+ _conn = null;
+ } catch (SQLException e) {
+ throw new CloudRuntimeException("Problem in closing a connection", e);
+ }
+ }
+
+ @Override
+ protected void finalize() throws Exception {
+ if (_conn != null) {
+ release();
+ }
+ }
+
+ public boolean keepAlive() {
+ return _keepAlive;
+ }
+
+ protected static class ConnectionConciergeManager extends StandardMBean implements ConnectionConciergeMBean {
+ ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("ConnectionKeeper"));
+ final ConcurrentHashMap<String, ConnectionConcierge> _conns = new ConcurrentHashMap<String, ConnectionConcierge>();
+ final AtomicInteger _idGenerator = new AtomicInteger();
+
+ ConnectionConciergeManager() {
+ super(ConnectionConciergeMBean.class, false);
+ resetKeepAliveTask(20);
+ try {
+ JmxUtil.registerMBean("DB Connections", "DB Connections", this);
+ } catch (Exception e) {
+ s_logger.error("Unable to register mbean", e);
+ }
+ }
+
+ public Integer getNextId() {
+ return _idGenerator.incrementAndGet();
+ }
+
+ public void register(String name, ConnectionConcierge concierge) {
+ _conns.put(name, concierge);
+ }
+
+ public void unregister(String name) {
+ _conns.remove(name);
+ }
+
+ protected String testValidity(String name, Connection conn) {
+ PreparedStatement pstmt = null;
+ try {
+ if (conn != null) {
+ pstmt = conn.prepareStatement("SELECT 1");
+ pstmt.executeQuery();
+ }
+ return null;
+ } catch (Throwable th) {
+ s_logger.error("Unable to keep the db connection for " + name, th);
+ return th.toString();
+ } finally {
+ if (pstmt != null) {
+ try {
+ pstmt.close();
+ } catch (SQLException e) {
+ }
+ }
+ }
+ }
+
+ @Override
+ public List<String> testValidityOfConnections() {
+ ArrayList<String> results = new ArrayList<String>(_conns.size());
+ for (Map.Entry<String, ConnectionConcierge> entry : _conns.entrySet()) {
+ String result = testValidity(entry.getKey(), entry.getValue().conn());
+ results.add(entry.getKey() + "=" + (result == null ? "OK" : result));
+ }
+ return results;
+ }
+
+ @Override
+ public String resetConnection(String name) {
+ ConnectionConcierge concierge = _conns.get(name);
+ if (concierge == null) {
+ return "Not Found";
+ }
+
+ Connection conn = Transaction.getStandaloneConnection();
+ if (conn == null) {
+ return "Unable to get anotehr db connection";
+ }
+
+ concierge.reset(conn);
+ return "Done";
+ }
+
+ @Override
+ public String resetKeepAliveTask(int seconds) {
+ if (_executor != null) {
+ try {
+ _executor.shutdown();
+ } catch(Exception e) {
+ s_logger.error("Unable to shutdown executor", e);
+ }
+ }
+
+ _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("ConnectionConcierge"));
+
+ _executor.scheduleAtFixedRate(new Runnable() {
+
+ @Override
+ public void run() {
+ s_logger.trace("connection concierge keep alive task");
+ for (Map.Entry<String, ConnectionConcierge> entry : _conns.entrySet()) {
+ ConnectionConcierge concierge = entry.getValue();
+ if (concierge.keepAlive()) {
+ testValidity(entry.getKey(), entry.getValue().conn());
+ }
+ }
+ }
+ }, 0, seconds, TimeUnit.SECONDS);
+
+ return "As you wish.";
+ }
+
+ @Override
+ public List<String> getConnectionsNotPooled() {
+ return new ArrayList<String>(_conns.keySet());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/framework/db/src/com/cloud/utils/db/ConnectionConciergeMBean.java
----------------------------------------------------------------------
diff --git a/framework/db/src/com/cloud/utils/db/ConnectionConciergeMBean.java b/framework/db/src/com/cloud/utils/db/ConnectionConciergeMBean.java
new file mode 100644
index 0000000..19a09cd
--- /dev/null
+++ b/framework/db/src/com/cloud/utils/db/ConnectionConciergeMBean.java
@@ -0,0 +1,30 @@
+// 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
+// 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 com.cloud.utils.db;
+
+import java.util.List;
+
+public interface ConnectionConciergeMBean {
+
+ List<String> testValidityOfConnections();
+
+ String resetConnection(String name);
+
+ String resetKeepAliveTask(int seconds);
+
+ List<String> getConnectionsNotPooled();
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/framework/db/src/com/cloud/utils/db/DB.java
----------------------------------------------------------------------
diff --git a/framework/db/src/com/cloud/utils/db/DB.java b/framework/db/src/com/cloud/utils/db/DB.java
new file mode 100644
index 0000000..f83a7ea
--- /dev/null
+++ b/framework/db/src/com/cloud/utils/db/DB.java
@@ -0,0 +1,59 @@
+// 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
+// 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 com.cloud.utils.db;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Running with assertions on, will find all classes that are
+ *
+ * 1. Annotate method that starts and commits DB transactions.
+ * Transaction txn = Transaction.currentTxn();
+ * txn.start();
+ * ...
+ * txn.commit();
+ *
+ * 2. Annotate methods that uses a DAO's acquire method.
+ * _dao.acquireInLockTable(id);
+ * ...
+ * _dao.releaseFromLockTable(id);
+ *
+ * 3. Annotate methods that are inside a DAO but doesn't use
+ * the Transaction class. Generally, these are methods
+ * that are utility methods for setting up searches. In
+ * this case use @DB(txn=false) to annotate the method.
+ * While this is not required, it helps when you're debugging
+ * the code and it saves on method calls during runtime.
+ *
+ */
+@Target({TYPE, METHOD})
+@Retention(RUNTIME)
+public @interface DB {
+ /**
+ * (Optional) Specifies that the method
+ * does not use transaction. This is useful for
+ * utility methods within DAO classes which are
+ * automatically marked with @DB. By marking txn=false,
+ * the method is not surrounded with transaction code.
+ */
+ boolean txn() default true;
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/framework/db/src/com/cloud/utils/db/DbUtil.java
----------------------------------------------------------------------
diff --git a/framework/db/src/com/cloud/utils/db/DbUtil.java b/framework/db/src/com/cloud/utils/db/DbUtil.java
new file mode 100755
index 0000000..da0efbb
--- /dev/null
+++ b/framework/db/src/com/cloud/utils/db/DbUtil.java
@@ -0,0 +1,342 @@
+// 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
+// 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 com.cloud.utils.db;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import javax.persistence.Embedded;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Id;
+import javax.persistence.PrimaryKeyJoinColumn;
+import javax.persistence.PrimaryKeyJoinColumns;
+import javax.persistence.SecondaryTable;
+import javax.persistence.SecondaryTables;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+
+import org.apache.log4j.Logger;
+
+public class DbUtil {
+ protected final static Logger s_logger = Logger.getLogger(DbUtil.class);
+
+ private static Map<String, Connection> s_connectionForGlobalLocks = new HashMap<String, Connection>();
+
+ public static Connection getConnectionForGlobalLocks(String name, boolean forLock) {
+ synchronized(s_connectionForGlobalLocks) {
+ if(forLock) {
+ if(s_connectionForGlobalLocks.get(name) != null) {
+ s_logger.error("Sanity check failed, global lock name " + name + " is already in use");
+ assert(false);
+ }
+
+ Connection connection = Transaction.getStandaloneConnection();
+ if(connection != null) {
+ try {
+ connection.setAutoCommit(true);
+ } catch (SQLException e) {
+ try {
+ connection.close();
+ } catch(SQLException sqlException) {
+ }
+ return null;
+ }
+ s_connectionForGlobalLocks.put(name, connection);
+ return connection;
+ }
+ return null;
+ } else {
+ Connection connection = s_connectionForGlobalLocks.get(name);
+ s_connectionForGlobalLocks.remove(name);
+ return connection;
+ }
+ }
+ }
+
+ public static void removeConnectionForGlobalLocks(String name) {
+ synchronized(s_connectionForGlobalLocks) {
+ s_connectionForGlobalLocks.remove(name);
+ }
+ }
+
+ public static String getColumnName(Field field, AttributeOverride[] overrides) {
+ if (overrides != null) {
+ for (AttributeOverride override : overrides) {
+ if (override.name().equals(field.getName())) {
+ return override.column().name();
+ }
+ }
+ }
+
+ assert(field.getAnnotation(Embedded.class) == null) : "Cannot get column name from embedded field: " + field.getName();
+
+ Column column = field.getAnnotation(Column.class);
+ return column != null ? column.name() : field.getName();
+ }
+
+ public static String getColumnName(Field field) {
+ return getColumnName(field, null);
+ }
+
+ public static String getReferenceColumn(PrimaryKeyJoinColumn pkjc) {
+ return pkjc.referencedColumnName().length() != 0
+ ? pkjc.referencedColumnName()
+ : pkjc.name();
+ }
+
+ public static PrimaryKeyJoinColumn[] getPrimaryKeyJoinColumns(Class<?> clazz) {
+ PrimaryKeyJoinColumn pkjc = clazz.getAnnotation(PrimaryKeyJoinColumn.class);
+ if (pkjc != null) {
+ return new PrimaryKeyJoinColumn[] { pkjc };
+ }
+
+ PrimaryKeyJoinColumns pkjcs = clazz.getAnnotation(PrimaryKeyJoinColumns.class);
+ if (pkjcs != null) {
+ return pkjcs.value();
+ }
+
+ return null;
+ }
+
+ public static Field findField(Class<?> clazz, String columnName) {
+ for (Field field : clazz.getDeclaredFields()) {
+ if (field.getAnnotation(Embedded.class) != null || field.getAnnotation(EmbeddedId.class) != null) {
+ findField(field.getClass(), columnName);
+ } else {
+ if (columnName.equals(DbUtil.getColumnName(field))) {
+ return field;
+ }
+ }
+ }
+ return null;
+ }
+
+ public static final AttributeOverride[] getAttributeOverrides(AnnotatedElement ae) {
+ AttributeOverride[] overrides = null;
+
+ AttributeOverrides aos = ae.getAnnotation(AttributeOverrides.class);
+ if (aos != null) {
+ overrides = aos.value();
+ }
+
+ if (overrides == null || overrides.length == 0) {
+ AttributeOverride override = ae.getAnnotation(AttributeOverride.class);
+ if (override != null) {
+ overrides = new AttributeOverride[1];
+ overrides[0] = override;
+ } else {
+ overrides = new AttributeOverride[0];
+ }
+ }
+
+ return overrides;
+ }
+
+ public static final boolean isPersistable(Field field) {
+ if (field.getAnnotation(Transient.class) != null) {
+ return false;
+ }
+
+ int modifiers = field.getModifiers();
+ return !(Modifier.isFinal(modifiers) ||
+ Modifier.isStatic(modifiers) ||
+ Modifier.isTransient(modifiers));
+ }
+
+ public static final boolean isIdField(Field field) {
+ if (field.getAnnotation(Id.class) != null) {
+ return true;
+ }
+
+ if (field.getAnnotation(EmbeddedId.class) != null) {
+ assert (field.getClass().getAnnotation(Embeddable.class) != null) : "Class " + field.getClass().getName() + " must be Embeddable to be used as Embedded Id";
+ return true;
+ }
+
+ return false;
+ }
+
+ public static final SecondaryTable[] getSecondaryTables(AnnotatedElement clazz) {
+ SecondaryTable[] sts = null;
+ SecondaryTable stAnnotation = clazz.getAnnotation(SecondaryTable.class);
+ if (stAnnotation == null) {
+ SecondaryTables stsAnnotation = clazz.getAnnotation(SecondaryTables.class);
+ sts = stsAnnotation != null ? stsAnnotation.value() : new SecondaryTable[0];
+ } else {
+ sts = new SecondaryTable[] {stAnnotation};
+ }
+
+ return sts;
+ }
+
+ public static final String getTableName(Class<?> clazz) {
+ Table table = clazz.getAnnotation(Table.class);
+ return table != null ? table.name() : clazz.getSimpleName();
+ }
+
+ public static boolean getGlobalLock(String name, int timeoutSeconds) {
+ Connection conn = getConnectionForGlobalLocks(name, true);
+ if(conn == null) {
+ s_logger.error("Unable to acquire DB connection for global lock system");
+ return false;
+ }
+
+ PreparedStatement pstmt = null;
+ try {
+ pstmt = conn.prepareStatement("SELECT COALESCE(GET_LOCK(?, ?),0)");
+
+ pstmt.setString(1, name);
+ pstmt.setInt(2, timeoutSeconds);
+
+ ResultSet rs = pstmt.executeQuery();
+ if (rs != null && rs.first()) {
+ if(rs.getInt(1) > 0) {
+ return true;
+ } else {
+ if(s_logger.isDebugEnabled())
+ s_logger.debug("GET_LOCK() timed out on lock : " + name);
+ }
+ }
+ } catch (SQLException e) {
+ s_logger.error("GET_LOCK() throws exception ", e);
+ } catch (Throwable e) {
+ s_logger.error("GET_LOCK() throws exception ", e);
+ } finally {
+ if (pstmt != null) {
+ try {
+ pstmt.close();
+ } catch (Throwable e) {
+ s_logger.error("What the heck? ", e);
+ }
+ }
+ }
+
+ removeConnectionForGlobalLocks(name);
+ try {
+ conn.close();
+ } catch (SQLException e) {
+ }
+ return false;
+ }
+
+
+ public static Class<?> getEntityBeanType(GenericDao<?, Long> dao) {
+ return dao.getEntityBeanType();
+ }
+
+ public static boolean releaseGlobalLock(String name) {
+ Connection conn = getConnectionForGlobalLocks(name, false);
+ if(conn == null) {
+ s_logger.error("Unable to acquire DB connection for global lock system");
+ assert(false);
+ return false;
+ }
+
+ PreparedStatement pstmt = null;
+ try {
+ pstmt = conn.prepareStatement("SELECT COALESCE(RELEASE_LOCK(?), 0)");
+ pstmt.setString(1, name);
+ ResultSet rs = pstmt.executeQuery();
+ if(rs != null && rs.first())
+ return rs.getInt(1) > 0;
+ s_logger.error("RELEASE_LOCK() returns unexpected result : " + rs.getInt(1));
+ } catch (SQLException e) {
+ s_logger.error("RELEASE_LOCK() throws exception ", e);
+ } catch (Throwable e) {
+ s_logger.error("RELEASE_LOCK() throws exception ", e);
+ } finally {
+ try {
+ if (pstmt != null) {
+ pstmt.close();
+ }
+ conn.close();
+ } catch(SQLException e) {
+ }
+ }
+ return false;
+ }
+
+ public static void closeResources(final Connection connection,
+ final Statement statement, final ResultSet resultSet) {
+
+ closeResultSet(resultSet);
+ closeStatement(statement);
+ closeConnection(connection);
+
+ }
+
+ public static void closeResources(final Statement statement, final ResultSet resultSet) {
+
+ closeResources(null, statement, resultSet);
+
+ }
+
+ public static void closeResultSet(final ResultSet resultSet) {
+
+ try {
+
+ if (resultSet != null) {
+ resultSet.close();
+ }
+
+ } catch (Exception e) {
+ s_logger.warn("Ignored exception while closing result set.",e);
+ }
+
+ }
+
+ public static void closeStatement(final Statement statement) {
+
+ try {
+
+ if (statement != null) {
+ statement.close();
+ }
+
+ } catch (Exception e) {
+ s_logger.warn("Ignored exception while closing statement.",e);
+ }
+
+ }
+
+ public static void closeConnection(final Connection connection) {
+
+ try {
+
+ if (connection != null) {
+ connection.close();
+ }
+
+ } catch (Exception e) {
+ s_logger.warn("Ignored exception while close connection.",e);
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/framework/db/src/com/cloud/utils/db/EcInfo.java
----------------------------------------------------------------------
diff --git a/framework/db/src/com/cloud/utils/db/EcInfo.java b/framework/db/src/com/cloud/utils/db/EcInfo.java
new file mode 100644
index 0000000..b33aa57
--- /dev/null
+++ b/framework/db/src/com/cloud/utils/db/EcInfo.java
@@ -0,0 +1,106 @@
+// 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
+// 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 com.cloud.utils.db;
+
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.CollectionTable;
+import javax.persistence.ElementCollection;
+import javax.persistence.JoinColumn;
+
+import com.cloud.utils.exception.CloudRuntimeException;
+
+public class EcInfo {
+ protected String insertSql;
+ protected String selectSql;
+ protected String clearSql;
+ protected Class<?> targetClass;
+ protected Class<?> rawClass;
+
+ public EcInfo(Attribute attr, Attribute idAttr) {
+ attr.attache = this;
+ ElementCollection ec = attr.field.getAnnotation(ElementCollection.class);
+ targetClass = ec.targetClass();
+ Class<?> type = attr.field.getType();
+ if (type.isArray()) {
+ rawClass = null;
+ } else {
+ ParameterizedType pType = (ParameterizedType)attr.field.getGenericType();
+ Type rawType = pType.getRawType();
+ Class<?> rawClazz = (Class<?>)rawType;
+ try {
+ if (!Modifier.isAbstract(rawClazz.getModifiers()) && !rawClazz.isInterface() && rawClazz.getConstructors().length != 0 && rawClazz.getConstructor() != null) {
+ rawClass = rawClazz;
+ } else if (Set.class == rawClazz) {
+ rawClass = HashSet.class;
+ } else if (List.class == rawClazz) {
+ rawClass = ArrayList.class;
+ } else if (Collection.class == Collection.class) {
+ rawClass = ArrayList.class;
+ } else {
+ assert (false) : " We don't know how to create this calss " + rawType.toString() + " for " + attr.field.getName();
+ }
+ } catch (NoSuchMethodException e) {
+ throw new CloudRuntimeException("Write your own support for " + rawClazz + " defined by " + attr.field.getName());
+ }
+ }
+
+ CollectionTable ct = attr.field.getAnnotation(CollectionTable.class);
+ assert (ct.name().length() > 0) : "Please sepcify the table for " + attr.field.getName();
+ StringBuilder selectBuf = new StringBuilder("SELECT ");
+ StringBuilder insertBuf = new StringBuilder("INSERT INTO ");
+ StringBuilder clearBuf = new StringBuilder("DELETE FROM ");
+
+ clearBuf.append(ct.name()).append(" WHERE ");
+ selectBuf.append(attr.columnName);
+ selectBuf.append(" FROM ").append(ct.name()).append(", ").append(attr.table);
+ selectBuf.append(" WHERE ");
+
+ insertBuf.append(ct.name()).append("(");
+ StringBuilder valuesBuf = new StringBuilder("SELECT ");
+
+ for (JoinColumn jc : ct.joinColumns()) {
+ selectBuf.append(ct.name()).append(".").append(jc.name()).append("=");
+ if (jc.referencedColumnName().length() == 0) {
+ selectBuf.append(idAttr.table).append(".").append(idAttr.columnName);
+ valuesBuf.append(idAttr.table).append(".").append(idAttr.columnName);
+ clearBuf.append(ct.name()).append(".").append(jc.name()).append("=?");
+ } else {
+ selectBuf.append(attr.table).append(".").append(jc.referencedColumnName());
+ valuesBuf.append(attr.table).append(".").append(jc.referencedColumnName()).append(",");
+ }
+ selectBuf.append(" AND ");
+ insertBuf.append(jc.name()).append(", ");
+ valuesBuf.append(", ");
+ }
+
+ selectSql = selectBuf.append(idAttr.table).append(".").append(idAttr.columnName).append("=?").toString();
+ insertBuf.append(attr.columnName).append(") ");
+ valuesBuf.append("? FROM ").append(attr.table);
+ valuesBuf.append(" WHERE ").append(idAttr.table).append(".").append(idAttr.columnName).append("=?");
+
+ insertSql = insertBuf.append(valuesBuf).toString();
+ clearSql = clearBuf.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/framework/db/src/com/cloud/utils/db/Encrypt.java
----------------------------------------------------------------------
diff --git a/framework/db/src/com/cloud/utils/db/Encrypt.java b/framework/db/src/com/cloud/utils/db/Encrypt.java
new file mode 100755
index 0000000..4973458
--- /dev/null
+++ b/framework/db/src/com/cloud/utils/db/Encrypt.java
@@ -0,0 +1,32 @@
+// 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
+// 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 com.cloud.utils.db;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Encrypt is a replacement for the column modification.
+ */
+@Target(FIELD)
+@Retention(RUNTIME)
+public @interface Encrypt {
+ boolean encrypt() default true;
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f5e5b39c/framework/db/src/com/cloud/utils/db/Filter.java
----------------------------------------------------------------------
diff --git a/framework/db/src/com/cloud/utils/db/Filter.java b/framework/db/src/com/cloud/utils/db/Filter.java
new file mode 100755
index 0000000..c9a4c8a
--- /dev/null
+++ b/framework/db/src/com/cloud/utils/db/Filter.java
@@ -0,0 +1,115 @@
+// 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
+// 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 com.cloud.utils.db;
+
+import java.lang.reflect.Field;
+
+import javax.persistence.Column;
+
+import com.cloud.utils.Pair;
+import com.cloud.utils.ReflectUtil;
+
+/**
+ * Try to use static initialization to help you in finding incorrect
+ * field names being passed in early.
+ *
+ * Something like the following:
+ * protected static final Filter s_NameFilter = new Filter(VMInstanceVO, name, true, null, null);
+ *
+ * Filter nameFilter = new Filter(s_nameFilter);
+ *
+ */
+public class Filter {
+ Long _offset;
+ Long _limit;
+ String _orderBy;
+
+ /**
+ * @param clazz the VO object type
+ * @param field name of the field
+ * @param offset
+ * @param limit
+ */
+ public Filter(Class<?> clazz, String field, boolean ascending, Long offset, Long limit) {
+ _offset = offset;
+ _limit = limit;
+
+ addOrderBy(clazz, field, ascending);
+ }
+
+ public Filter(long limit) {
+ _orderBy = " ORDER BY RAND() LIMIT " + limit;
+ }
+
+ /**
+ * Note that this copy constructor does not copy offset and limit.
+ * @param that filter
+ */
+ public Filter(Filter that) {
+ this._orderBy = that._orderBy;
+ this._limit = null;
+ that._limit = null;
+ }
+
+ public void addOrderBy(Class<?> clazz, String field, boolean ascending) {
+ if (field == null) {
+ return;
+ }
+ Field f;
+ Pair<Class<?>, Field> pair = ReflectUtil.getAnyField(clazz, field);
+ assert(pair != null) : "Can't find field " + field + " in " + clazz.getName();
+ clazz = pair.first();
+ f = pair.second();
+
+ Column column = f.getAnnotation(Column.class);
+ String name = column != null ? column.name() : field;
+
+ StringBuilder order = new StringBuilder();
+ if (column.table() == null || column.table().length() == 0) {
+ order.append(DbUtil.getTableName(clazz));
+ } else {
+ order.append(column.table());
+ }
+ order.append(".").append(name).append(ascending ? " ASC " : " DESC ");
+
+ if (_orderBy == null) {
+ _orderBy = order.insert(0, " ORDER BY ").toString();
+ } else {
+ _orderBy = order.insert(0, _orderBy).toString();
+ }
+ }
+
+ public String getOrderBy() {
+ return _orderBy;
+ }
+
+ public void setOffset(Long offset) {
+ _offset = offset;
+ }
+
+ public Long getOffset() {
+ return _offset;
+ }
+
+ public Long getLimit() {
+ return _limit;
+ }
+
+ public void setLimit(Long limit) {
+ _limit = limit;
+ }
+}