You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by bh...@apache.org on 2012/12/07 18:59:21 UTC

git commit: api: Refactor ResourceTagResponse and ListTagsCmd, add db view for ResourceTag.

Updated Branches:
  refs/heads/api_refactoring 2bbd023eb -> acf7afd7f


api: Refactor ResourceTagResponse and ListTagsCmd, add db view for ResourceTag.

Signed-off-by: Rohit Yadav <bh...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/commit/acf7afd7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/tree/acf7afd7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/diff/acf7afd7

Branch: refs/heads/api_refactoring
Commit: acf7afd7f5139e05ecba29b715c2a20d5f28d3c0
Parents: 2bbd023
Author: Min Chen <mi...@citrix.com>
Authored: Fri Dec 7 09:40:16 2012 -0800
Committer: Rohit Yadav <bh...@apache.org>
Committed: Fri Dec 7 09:57:52 2012 -0800

----------------------------------------------------------------------
 .../cloud/api/response/ResourceTagResponse.java    |   23 +-
 .../com/cloud/api/view/vo/ResourceTagJoinVO.java   |  284 +++++++++++++++
 .../com/cloud/server/TaggedResourceService.java    |    4 +-
 .../apache/cloudstack/api/ResponseGenerator.java   |    4 +
 .../api/user/tag/command/ListTagsCmd.java          |   10 +-
 server/src/com/cloud/api/ApiDBUtils.java           |   28 ++-
 server/src/com/cloud/api/ApiResponseHelper.java    |  158 ++++-----
 .../configuration/DefaultComponentLibrary.java     |    2 +
 .../security/dao/SecurityGroupJoinDaoImpl.java     |   51 +---
 .../com/cloud/tags/TaggedResourceManagerImpl.java  |   23 +-
 .../src/com/cloud/tags/dao/ResourceTagJoinDao.java |   34 ++
 .../com/cloud/tags/dao/ResourceTagJoinDaoImpl.java |  137 +++++++
 server/src/com/cloud/vm/dao/UserVmJoinDaoImpl.java |   51 +---
 setup/db/create-schema.sql                         |   28 ++
 14 files changed, 631 insertions(+), 206 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/acf7afd7/api/src/com/cloud/api/response/ResourceTagResponse.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/api/response/ResourceTagResponse.java b/api/src/com/cloud/api/response/ResourceTagResponse.java
index 04c2290..4f94e99 100644
--- a/api/src/com/cloud/api/response/ResourceTagResponse.java
+++ b/api/src/com/cloud/api/response/ResourceTagResponse.java
@@ -22,7 +22,7 @@ import com.cloud.utils.IdentityProxy;
 import com.google.gson.annotations.SerializedName;
 
 @SuppressWarnings("unused")
-public class ResourceTagResponse extends BaseResponse implements ControlledEntityResponse{
+public class ResourceTagResponse extends BaseResponse implements ControlledViewEntityResponse{
     @SerializedName(ApiConstants.KEY) @Param(description="tag key name")
     private String key;
 
@@ -33,21 +33,21 @@ public class ResourceTagResponse extends BaseResponse implements ControlledEntit
     private String resourceType;
 
     @SerializedName(ApiConstants.RESOURCE_ID) @Param(description="id of the resource")
-    private String id;
+    private String resourceId;
 
     @SerializedName(ApiConstants.ACCOUNT)
     @Param(description = "the account associated with the tag")
     private String accountName;
 
     @SerializedName(ApiConstants.PROJECT_ID) @Param(description="the project id the tag belongs to")
-    private IdentityProxy projectId = new IdentityProxy("projects");
+    private String projectId;
 
     @SerializedName(ApiConstants.PROJECT) @Param(description="the project name where tag belongs to")
     private String projectName;
 
     @SerializedName(ApiConstants.DOMAIN_ID)
     @Param(description = "the ID of the domain associated with the tag")
-    private IdentityProxy domainId = new IdentityProxy("domain");
+    private String domainId;
 
     @SerializedName(ApiConstants.DOMAIN)
     @Param(description = "the domain associated with the tag")
@@ -68,25 +68,28 @@ public class ResourceTagResponse extends BaseResponse implements ControlledEntit
         this.resourceType = resourceType;
     }
 
-    public void setId(String id) {
-        this.id = id;
+    public void setResourceId(String id) {
+        this.resourceId = id;
     }
 
+    @Override
     public void setAccountName(String accountName) {
         this.accountName = accountName;
     }
 
-    public void setDomainId(Long domainId) {
-        this.domainId.setValue(domainId);
+    @Override
+    public void setDomainId(String domainId) {
+        this.domainId = domainId;
     }
 
+    @Override
     public void setDomainName(String domainName) {
         this.domainName = domainName;
     }
 
     @Override
-    public void setProjectId(Long projectId) {
-        this.projectId.setValue(projectId);
+    public void setProjectId(String projectId) {
+        this.projectId = projectId;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/acf7afd7/api/src/com/cloud/api/view/vo/ResourceTagJoinVO.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/api/view/vo/ResourceTagJoinVO.java b/api/src/com/cloud/api/view/vo/ResourceTagJoinVO.java
new file mode 100644
index 0000000..070720b
--- /dev/null
+++ b/api/src/com/cloud/api/view/vo/ResourceTagJoinVO.java
@@ -0,0 +1,284 @@
+// 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.api.view.vo;
+
+import java.net.URI;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.Table;
+
+import com.cloud.network.Network.GuestType;
+import com.cloud.network.Networks.TrafficType;
+import com.cloud.network.router.VirtualRouter.RedundantState;
+import com.cloud.network.security.SecurityRule.SecurityRuleType;
+import com.cloud.server.ResourceTag.TaggedResourceType;
+import com.cloud.utils.db.GenericDao;
+import com.cloud.vm.VirtualMachine.State;
+
+@Entity
+@Table(name="resource_tag_view")
+public class ResourceTagJoinVO implements ControlledViewEntity {
+
+    @Column(name="id", updatable=false, nullable = false)
+    private long id;
+
+    @Column(name="uuid")
+    private String uuid;
+
+    @Column(name="key")
+    private String key;
+
+    @Column(name="value")
+    String value;
+
+
+
+    @Column(name="resource_id")
+    long resourceId;
+
+    @Column(name="resource_uuid")
+    private String resourceUuid;
+
+    @Column(name="resource_type")
+    @Enumerated(value=EnumType.STRING)
+    private TaggedResourceType resourceType;
+
+    @Column(name="customer")
+    String customer;
+
+
+
+    @Column(name="account_id")
+    private long accountId;
+
+    @Column(name="account_uuid")
+    private String accountUuid;
+
+    @Column(name="account_name")
+    private String accountName = null;
+
+    @Column(name="account_type")
+    private short accountType;
+
+    @Column(name="domain_id")
+    private long domainId;
+
+    @Column(name="domain_uuid")
+    private String domainUuid;
+
+    @Column(name="domain_name")
+    private String domainName = null;
+
+    @Column(name="domain_path")
+    private String domainPath = null;
+
+    @Column(name="project_id")
+    private long projectId;
+
+    @Column(name="project_uuid")
+    private String projectUuid;
+
+    @Column(name="project_name")
+    private String projectName;
+
+
+
+    public ResourceTagJoinVO() {
+    }
+
+    public String getUuid() {
+        return uuid;
+    }
+
+    public void setUuid(String uuid) {
+        this.uuid = uuid;
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+
+    public long getAccountId() {
+        return accountId;
+    }
+
+    public void setAccountId(long accountId) {
+        this.accountId = accountId;
+    }
+
+    public String getAccountUuid() {
+        return accountUuid;
+    }
+
+    public void setAccountUuid(String accountUuid) {
+        this.accountUuid = accountUuid;
+    }
+
+    public String getAccountName() {
+        return accountName;
+    }
+
+    public void setAccountName(String accountName) {
+        this.accountName = accountName;
+    }
+
+    public short getAccountType() {
+        return accountType;
+    }
+
+    public void setAccountType(short accountType) {
+        this.accountType = accountType;
+    }
+
+    public long getDomainId() {
+        return domainId;
+    }
+
+    public void setDomainId(long domainId) {
+        this.domainId = domainId;
+    }
+
+    @Override
+    public String getDomainUuid() {
+        return domainUuid;
+    }
+
+    public void setDomainUuid(String domainUuid) {
+        this.domainUuid = domainUuid;
+    }
+
+    public String getDomainName() {
+        return domainName;
+    }
+
+    public void setDomainName(String domainName) {
+        this.domainName = domainName;
+    }
+
+    public String getDomainPath() {
+        return domainPath;
+    }
+
+    public void setDomainPath(String domainPath) {
+        this.domainPath = domainPath;
+    }
+
+    public long getProjectId() {
+        return projectId;
+    }
+
+    public void setProjectId(long projectId) {
+        this.projectId = projectId;
+    }
+
+    public String getProjectUuid() {
+        return projectUuid;
+    }
+
+    public void setProjectUuid(String projectUuid) {
+        this.projectUuid = projectUuid;
+    }
+
+    public String getProjectName() {
+        return projectName;
+    }
+
+    public void setProjectName(String projectName) {
+        this.projectName = projectName;
+    }
+
+
+
+    public String getKey() {
+        return key;
+    }
+
+    public void setKey(String key) {
+        this.key = key;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public long getResourceId() {
+        return resourceId;
+    }
+
+    public void setResourceId(long resourceId) {
+        this.resourceId = resourceId;
+    }
+
+    public String getResourceUuid() {
+        return resourceUuid;
+    }
+
+    public void setResourceUuid(String resourceUuid) {
+        this.resourceUuid = resourceUuid;
+    }
+
+    public TaggedResourceType getResourceType() {
+        return resourceType;
+    }
+
+    public void setResourceType(TaggedResourceType resourceType) {
+        this.resourceType = resourceType;
+    }
+
+    public String getCustomer() {
+        return customer;
+    }
+
+    public void setCustomer(String customer) {
+        this.customer = customer;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + (int) (id ^ (id >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        ResourceTagJoinVO other = (ResourceTagJoinVO) obj;
+        if (id != other.id)
+            return false;
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/acf7afd7/api/src/com/cloud/server/TaggedResourceService.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/server/TaggedResourceService.java b/api/src/com/cloud/server/TaggedResourceService.java
index c98b02b..667a023 100644
--- a/api/src/com/cloud/server/TaggedResourceService.java
+++ b/api/src/com/cloud/server/TaggedResourceService.java
@@ -20,6 +20,8 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.cloudstack.api.user.tag.command.ListTagsCmd;
+
+import com.cloud.api.view.vo.ResourceTagJoinVO;
 import com.cloud.server.ResourceTag.TaggedResourceType;
 import com.cloud.utils.Pair;
 
@@ -47,7 +49,7 @@ public interface TaggedResourceService {
      * @param listTagsCmd
      * @return
      */
-    Pair<List<? extends ResourceTag>, Integer> listTags(ListTagsCmd listTagsCmd);
+    Pair<List<ResourceTagJoinVO>, Integer> listTags(ListTagsCmd listTagsCmd);
 
     /**
      * @param resourceIds

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/acf7afd7/api/src/org/apache/cloudstack/api/ResponseGenerator.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/org/apache/cloudstack/api/ResponseGenerator.java
index 96df77e..4f0c804 100755
--- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java
+++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java
@@ -153,6 +153,7 @@ import com.cloud.user.UserAccount;
 import com.cloud.uservm.UserVm;
 import com.cloud.vm.InstanceGroup;
 import com.cloud.api.view.vo.DomainRouterJoinVO;
+import com.cloud.api.view.vo.ResourceTagJoinVO;
 import com.cloud.api.view.vo.SecurityGroupJoinVO;
 import com.cloud.api.view.vo.UserVmJoinVO;
 import com.cloud.vm.VirtualMachine;
@@ -327,6 +328,9 @@ public interface ResponseGenerator {
      */
     ResourceTagResponse createResourceTagResponse(ResourceTag resourceTag, boolean keyValueOnly);
 
+    List<ResourceTagResponse> createResourceTagResponse(boolean keyValueOnly, ResourceTagJoinVO... resourceTag);
+
+
     Site2SiteVpnGatewayResponse createSite2SiteVpnGatewayResponse(Site2SiteVpnGateway result);
 
 

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/acf7afd7/api/src/org/apache/cloudstack/api/user/tag/command/ListTagsCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/user/tag/command/ListTagsCmd.java b/api/src/org/apache/cloudstack/api/user/tag/command/ListTagsCmd.java
index ef95439..28f895b 100644
--- a/api/src/org/apache/cloudstack/api/user/tag/command/ListTagsCmd.java
+++ b/api/src/org/apache/cloudstack/api/user/tag/command/ListTagsCmd.java
@@ -26,6 +26,7 @@ import org.apache.cloudstack.api.Implementation;
 import org.apache.cloudstack.api.Parameter;
 import com.cloud.api.response.ListResponse;
 import com.cloud.api.response.ResourceTagResponse;
+import com.cloud.api.view.vo.ResourceTagJoinVO;
 import com.cloud.server.ResourceTag;
 import com.cloud.utils.Pair;
 
@@ -56,15 +57,10 @@ public class ListTagsCmd extends BaseListProjectAndAccountResourcesCmd{
     @Override
     public void execute() {
 
-      Pair<List<? extends ResourceTag>, Integer> tags = _taggedResourceService.listTags(this);
+      Pair<List<ResourceTagJoinVO>, Integer> tags = _taggedResourceService.listTags(this);
       ListResponse<ResourceTagResponse> response = new ListResponse<ResourceTagResponse>();
-      List<ResourceTagResponse> tagResponses = new ArrayList<ResourceTagResponse>();
-      for (ResourceTag tag : tags.first()) {
-          ResourceTagResponse tagResponse = _responseGenerator.createResourceTagResponse(tag, false);
-          tagResponses.add(tagResponse);
-      }
+      List<ResourceTagResponse> tagResponses = _responseGenerator.createResourceTagResponse(false, tags.first().toArray(new ResourceTagJoinVO[tags.first().size()]));
       response.setResponses(tagResponses, tags.second());
-
       response.setResponseName(getCommandName());
       this.setResponseObject(response);
     }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/acf7afd7/server/src/com/cloud/api/ApiDBUtils.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java
index b48cbe6..b537bcb 100755
--- a/server/src/com/cloud/api/ApiDBUtils.java
+++ b/server/src/com/cloud/api/ApiDBUtils.java
@@ -24,9 +24,11 @@ import java.util.Set;
 
 import org.apache.cloudstack.api.ApiConstants.VMDetails;
 import com.cloud.api.response.DomainRouterResponse;
+import com.cloud.api.response.ResourceTagResponse;
 import com.cloud.api.response.SecurityGroupResponse;
 import com.cloud.api.response.UserVmResponse;
 import com.cloud.api.view.vo.DomainRouterJoinVO;
+import com.cloud.api.view.vo.ResourceTagJoinVO;
 import com.cloud.api.view.vo.SecurityGroupJoinVO;
 import com.cloud.api.view.vo.UserVmJoinVO;
 import com.cloud.async.AsyncJobManager;
@@ -141,6 +143,7 @@ import com.cloud.storage.dao.VMTemplateHostDao;
 import com.cloud.storage.dao.VMTemplateSwiftDao;
 import com.cloud.storage.dao.VolumeDao;
 import com.cloud.storage.dao.VolumeHostDao;
+import com.cloud.tags.dao.ResourceTagJoinDao;
 import com.cloud.user.Account;
 import com.cloud.user.AccountDetailsDao;
 import com.cloud.user.AccountVO;
@@ -243,6 +246,8 @@ public class ApiDBUtils {
     private static AutoScaleVmGroupPolicyMapDao _asVmGroupPolicyMapDao;
     private static AutoScalePolicyDao _asPolicyDao;
     private static CounterDao _counterDao;
+    private static ResourceTagJoinDao _tagJoinDao;
+
     static {
         _ms = (ManagementServer) ComponentLocator.getComponent(ManagementServer.Name);
         ComponentLocator locator = ComponentLocator.getLocator(ManagementServer.Name);
@@ -311,6 +316,7 @@ public class ApiDBUtils {
         _asVmGroupPolicyMapDao = locator.getDao(AutoScaleVmGroupPolicyMapDao.class);
         _asVmGroupPolicyMapDao = locator.getDao(AutoScaleVmGroupPolicyMapDao.class);
         _counterDao = locator.getDao(CounterDao.class);
+        _tagJoinDao = locator.getDao(ResourceTagJoinDao.class);
 
         // Note: stats collector should already have been initialized by this time, otherwise a null instance is returned
         _statsCollector = StatsCollector.getInstance();
@@ -616,8 +622,8 @@ public class ApiDBUtils {
         return _site2SiteVpnGatewayDao.findById(vpnGatewayId);
     }
     
-    public static Site2SiteCustomerGatewayVO findCustomerGatewayById(Long customerGatewayId) {    	
-    	return _site2SiteCustomerGatewayDao.findById(customerGatewayId);
+    public static Site2SiteCustomerGatewayVO findCustomerGatewayById(Long customerGatewayId) {      
+        return _site2SiteCustomerGatewayDao.findById(customerGatewayId);
     }
     
     public static List<UserVO> listUsersByAccount(long accountId) {
@@ -946,4 +952,22 @@ public class ApiDBUtils {
     public static List<SecurityGroupJoinVO> findSecurityGroupViewById(Long sgId){
         return _securityGroupJoinDao.searchByIds(sgId);
     }
+
+    public static ResourceTagResponse newResourceTagResponse(ResourceTagJoinVO vsg, boolean keyValueOnly) {
+        return _tagJoinDao.newResourceTagResponse(vsg, keyValueOnly);
+    }
+
+    public static ResourceTagJoinVO newResourceTagView(ResourceTag sg){
+        return _tagJoinDao.newResourceTagView(sg);
+    }
+
+    public static ResourceTagJoinVO findResourceTagViewById(Long tagId){
+        List<ResourceTagJoinVO> tags = _tagJoinDao.searchByIds(tagId);
+        if ( tags != null && tags.size() > 0 ){
+            return tags.get(0);
+        }
+        else{
+            return null;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/acf7afd7/server/src/com/cloud/api/ApiResponseHelper.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java
index ca39e8d..7bb2f5e 100755
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -118,6 +118,7 @@ import com.cloud.api.response.VpnUsersResponse;
 import com.cloud.api.response.ZoneResponse;
 import com.cloud.api.view.vo.DomainRouterJoinVO;
 import com.cloud.api.view.vo.ControlledViewEntity;
+import com.cloud.api.view.vo.ResourceTagJoinVO;
 import com.cloud.api.view.vo.SecurityGroupJoinVO;
 import com.cloud.api.view.vo.UserVmJoinVO;
 import com.cloud.async.AsyncJob;
@@ -1080,27 +1081,27 @@ public class ApiResponseHelper implements ResponseGenerator {
         volResponse.setVolumeType(volume.getVolumeType().toString());
         volResponse.setDeviceId(volume.getDeviceId());
         
-        	Long instanceId = volume.getInstanceId();
-	        if (instanceId != null && volume.getState() != Volume.State.Destroy) {
-	            VMInstanceVO vm = ApiDBUtils.findVMInstanceById(instanceId);
-	            if (vm != null) {
-	                volResponse.setVirtualMachineId(vm.getId());
-	                volResponse.setVirtualMachineName(vm.getHostName());
-	                UserVm userVm = ApiDBUtils.findUserVmById(vm.getId());
-	                if (userVm != null) {
-	                    if (userVm.getDisplayName() != null) {
-	                        volResponse.setVirtualMachineDisplayName(userVm.getDisplayName());
-	                    } else {
-	                        volResponse.setVirtualMachineDisplayName(userVm.getHostName());
-	                    }
-	                    volResponse.setVirtualMachineState(vm.getState().toString());
-	                } else {
-	                    s_logger.error("User Vm with Id: " + instanceId + " does not exist for volume " + volume.getId());
-	                }
-	            } else {
-	                s_logger.error("Vm with Id: " + instanceId + " does not exist for volume " + volume.getId());
-	            }
-	        }
+            Long instanceId = volume.getInstanceId();
+            if (instanceId != null && volume.getState() != Volume.State.Destroy) {
+                VMInstanceVO vm = ApiDBUtils.findVMInstanceById(instanceId);
+                if (vm != null) {
+                    volResponse.setVirtualMachineId(vm.getId());
+                    volResponse.setVirtualMachineName(vm.getHostName());
+                    UserVm userVm = ApiDBUtils.findUserVmById(vm.getId());
+                    if (userVm != null) {
+                        if (userVm.getDisplayName() != null) {
+                            volResponse.setVirtualMachineDisplayName(userVm.getDisplayName());
+                        } else {
+                            volResponse.setVirtualMachineDisplayName(userVm.getHostName());
+                        }
+                        volResponse.setVirtualMachineState(vm.getState().toString());
+                    } else {
+                        s_logger.error("User Vm with Id: " + instanceId + " does not exist for volume " + volume.getId());
+                    }
+                } else {
+                    s_logger.error("Vm with Id: " + instanceId + " does not exist for volume " + volume.getId());
+                }
+            }
 
         // Show the virtual size of the volume
         volResponse.setSize(volume.getSize());
@@ -1108,7 +1109,7 @@ public class ApiResponseHelper implements ResponseGenerator {
         volResponse.setCreated(volume.getCreated());
         volResponse.setState(volume.getState().toString());
         if(volume.getState() == Volume.State.UploadOp){
-        	com.cloud.storage.VolumeHostVO volumeHostRef = ApiDBUtils.findVolumeHostRef(volume.getId(), volume.getDataCenterId());
+            com.cloud.storage.VolumeHostVO volumeHostRef = ApiDBUtils.findVolumeHostRef(volume.getId(), volume.getDataCenterId());
             volResponse.setSize(volumeHostRef.getSize());
             volResponse.setCreated(volumeHostRef.getCreated());
             Account caller = UserContext.current().getCaller();
@@ -1126,17 +1127,17 @@ public class ApiResponseHelper implements ResponseGenerator {
                 } else {
                     volumeStatus = volumeHostRef.getErrorString();
                     if(volumeHostRef.getDownloadState() == VMTemplateHostVO.Status.NOT_DOWNLOADED){
-                    	volResponse.setState("UploadNotStarted");
+                        volResponse.setState("UploadNotStarted");
                     }else {
-                    	volResponse.setState("UploadError");
+                        volResponse.setState("UploadError");
                     }
                 }
                 volResponse.setStatus(volumeStatus);
             } else if (volumeHostRef.getDownloadState() == VMTemplateHostVO.Status.DOWNLOADED) {
-            	volResponse.setStatus("Upload Complete");
-            	volResponse.setState("Uploaded");
+                volResponse.setStatus("Upload Complete");
+                volResponse.setState("Uploaded");
             } else {
-            	volResponse.setStatus("Successfully Installed");
+                volResponse.setStatus("Successfully Installed");
             }
         }
 
@@ -1169,27 +1170,27 @@ public class ApiResponseHelper implements ResponseGenerator {
         // return hypervisor for ROOT and Resource domain only
         Account caller = UserContext.current().getCaller();
         if ((caller.getType() == Account.ACCOUNT_TYPE_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) && volume.getState() != Volume.State.UploadOp) {            
-        	volResponse.setHypervisor(ApiDBUtils.getVolumeHyperType(volume.getId()).toString());            
+            volResponse.setHypervisor(ApiDBUtils.getVolumeHyperType(volume.getId()).toString());            
         }
 
         volResponse.setAttached(volume.getAttached());
         volResponse.setDestroyed(volume.getState() == Volume.State.Destroy);
-	        boolean isExtractable = true;
-	        if (volume.getVolumeType() != Volume.Type.DATADISK) { // Datadisk dont have any template dependence.
-	            VMTemplateVO template = ApiDBUtils.findTemplateById(volume.getTemplateId());
+            boolean isExtractable = true;
+            if (volume.getVolumeType() != Volume.Type.DATADISK) { // Datadisk dont have any template dependence.
+                VMTemplateVO template = ApiDBUtils.findTemplateById(volume.getTemplateId());
             if (template != null) { // For ISO based volumes template = null and we allow extraction of all ISO based volumes
-	                isExtractable = template.isExtractable() && template.getTemplateType() != Storage.TemplateType.SYSTEM;
-	            }
-	        }
-	
-	        //set tag information
-	        List<? extends ResourceTag> tags = ApiDBUtils.listByResourceTypeAndId(TaggedResourceType.Volume, volume.getId());
-	        List<ResourceTagResponse> tagResponses = new ArrayList<ResourceTagResponse>();
-	        for (ResourceTag tag : tags) {
-	            ResourceTagResponse tagResponse = createResourceTagResponse(tag, true);
-	            tagResponses.add(tagResponse);
-	        }
-	        volResponse.setTags(tagResponses);
+                    isExtractable = template.isExtractable() && template.getTemplateType() != Storage.TemplateType.SYSTEM;
+                }
+            }
+    
+            //set tag information
+            List<? extends ResourceTag> tags = ApiDBUtils.listByResourceTypeAndId(TaggedResourceType.Volume, volume.getId());
+            List<ResourceTagResponse> tagResponses = new ArrayList<ResourceTagResponse>();
+            for (ResourceTag tag : tags) {
+                ResourceTagResponse tagResponse = createResourceTagResponse(tag, true);
+                tagResponses.add(tagResponse);
+            }
+            volResponse.setTags(tagResponses);
 
         volResponse.setExtractable(isExtractable);
         volResponse.setObjectName("volume");
@@ -2593,7 +2594,7 @@ public class ApiResponseHelper implements ResponseGenerator {
             response.setBroadcastUri(broadcastUri);
             String vlan="N/A";
             if (broadcastUri.startsWith("vlan")) {
-            	vlan = broadcastUri.substring("vlan://".length(), broadcastUri.length());
+                vlan = broadcastUri.substring("vlan://".length(), broadcastUri.length());
             }
             //return vlan information only to Root admin
             response.setVlan(vlan);
@@ -3159,42 +3160,21 @@ public class ApiResponseHelper implements ResponseGenerator {
 
     @Override
     public ResourceTagResponse createResourceTagResponse(ResourceTag resourceTag, boolean keyValueOnly) {
-        ResourceTagResponse response = new ResourceTagResponse();
-        response.setKey(resourceTag.getKey());
-        response.setValue(resourceTag.getValue());
-
-        if (!keyValueOnly) {
-        response.setResourceType(resourceTag.getResourceType().toString());        
-        response.setId(ApiDBUtils.getUuid(String.valueOf(resourceTag.getResourceId()),resourceTag.getResourceType()));
-        Long accountId = resourceTag.getAccountId();
-        Long domainId = resourceTag.getDomainId();
-        if (accountId != null) {
-            Account account = ApiDBUtils.findAccountByIdIncludingRemoved(resourceTag.getAccountId());
-
-            if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) {
-                // find the project
-                Project project = ApiDBUtils.findProjectByProjectAccountIdIncludingRemoved(account.getId());
-                response.setProjectId(project.getId());
-                response.setProjectName(project.getName());
-            } else {
-                response.setAccountName(account.getAccountName());
-            }
-        }
-        
-        if (domainId != null) {
-            response.setDomainId(domainId);
-            response.setDomainName(ApiDBUtils.findDomainById(domainId).getName());
-        }
-        
-        response.setCustomer(resourceTag.getCustomer());
-        }
-        
-        response.setObjectName("ag");
-  
-        return response;
+        ResourceTagJoinVO rto = ApiDBUtils.newResourceTagView(resourceTag);
+        return ApiDBUtils.newResourceTagResponse(rto, keyValueOnly);
     }
+
     
     @Override
+    public List<ResourceTagResponse> createResourceTagResponse(boolean keyValueOnly, ResourceTagJoinVO... tags) {
+        List<ResourceTagResponse> respList = new ArrayList<ResourceTagResponse>();
+        for (ResourceTagJoinVO vt : tags){
+            respList.add(ApiDBUtils.newResourceTagResponse(vt, keyValueOnly));
+        }
+        return respList;
+    }
+
+    @Override
     public VpcOfferingResponse createVpcOfferingResponse(VpcOffering offering) {
         VpcOfferingResponse response = new VpcOfferingResponse();
         response.setId(offering.getId());
@@ -3442,7 +3422,7 @@ public class ApiResponseHelper implements ResponseGenerator {
     
     @Override
     public Site2SiteVpnGatewayResponse createSite2SiteVpnGatewayResponse(Site2SiteVpnGateway result) {
-    	Site2SiteVpnGatewayResponse response = new Site2SiteVpnGatewayResponse();
+        Site2SiteVpnGatewayResponse response = new Site2SiteVpnGatewayResponse();
         response.setId(result.getId());
         response.setIp(ApiDBUtils.findIpAddressById(result.getAddrId()).getAddress().toString());
         response.setVpcId(result.getVpcId());
@@ -3485,22 +3465,22 @@ public class ApiResponseHelper implements ResponseGenerator {
         response.setVpnGatewayId(result.getVpnGatewayId()); 
         Long vpnGatewayId = result.getVpnGatewayId();
         if(vpnGatewayId != null) {
-        	Site2SiteVpnGatewayVO vpnGateway = ApiDBUtils.findVpnGatewayById(vpnGatewayId);
-        	
-        	long ipId = vpnGateway.getAddrId();
-        	IPAddressVO ipObj = ApiDBUtils.findIpAddressById(ipId);
-        	response.setIp(ipObj.getAddress().addr());  
+            Site2SiteVpnGatewayVO vpnGateway = ApiDBUtils.findVpnGatewayById(vpnGatewayId);
+            
+            long ipId = vpnGateway.getAddrId();
+            IPAddressVO ipObj = ApiDBUtils.findIpAddressById(ipId);
+            response.setIp(ipObj.getAddress().addr());  
         }
         
         response.setCustomerGatewayId(result.getCustomerGatewayId()); 
         Long customerGatewayId = result.getCustomerGatewayId();
         if(customerGatewayId != null) {
-        	Site2SiteCustomerGatewayVO customerGateway = ApiDBUtils.findCustomerGatewayById(customerGatewayId);
-        	response.setGatewayIp(customerGateway.getGatewayIp());
-        	response.setGuestCidrList(customerGateway.getGuestCidrList());
-        	response.setIpsecPsk(customerGateway.getIpsecPsk());
-        	response.setIkePolicy(customerGateway.getIkePolicy());
-        	response.setEspPolicy(customerGateway.getEspPolicy());
+            Site2SiteCustomerGatewayVO customerGateway = ApiDBUtils.findCustomerGatewayById(customerGatewayId);
+            response.setGatewayIp(customerGateway.getGatewayIp());
+            response.setGuestCidrList(customerGateway.getGuestCidrList());
+            response.setIpsecPsk(customerGateway.getIpsecPsk());
+            response.setIkePolicy(customerGateway.getIkePolicy());
+            response.setEspPolicy(customerGateway.getEspPolicy());
                 response.setIkeLifetime(customerGateway.getIkeLifetime());
                 response.setEspLifetime(customerGateway.getEspLifetime());
                 response.setDpd(customerGateway.getDpd());

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/acf7afd7/server/src/com/cloud/configuration/DefaultComponentLibrary.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/DefaultComponentLibrary.java b/server/src/com/cloud/configuration/DefaultComponentLibrary.java
index 1e292c4..89313e9 100755
--- a/server/src/com/cloud/configuration/DefaultComponentLibrary.java
+++ b/server/src/com/cloud/configuration/DefaultComponentLibrary.java
@@ -171,6 +171,7 @@ import com.cloud.storage.snapshot.SnapshotSchedulerImpl;
 import com.cloud.storage.swift.SwiftManagerImpl;
 import com.cloud.storage.upload.UploadMonitorImpl;
 import com.cloud.tags.TaggedResourceManagerImpl;
+import com.cloud.tags.dao.ResourceTagJoinDaoImpl;
 import com.cloud.tags.dao.ResourceTagsDaoImpl;
 import com.cloud.template.HyervisorTemplateAdapter;
 import com.cloud.template.TemplateAdapter;
@@ -222,6 +223,7 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com
         addDao("UserVmJoinDao", UserVmJoinDaoImpl.class);
         addDao("DomainRouterJoinDao", DomainRouterJoinDaoImpl.class);
         addDao("SecurityGroupJoinDao", SecurityGroupJoinDaoImpl.class);
+        addDao("ResourceTagJoinDao", ResourceTagJoinDaoImpl.class);
         ComponentInfo<? extends GenericDao<?, ? extends Serializable>> info = addDao("ServiceOfferingDao", ServiceOfferingDaoImpl.class);
         info.addParameter("cache.size", "50");
         info.addParameter("cache.time.to.live", "600");

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/acf7afd7/server/src/com/cloud/network/security/dao/SecurityGroupJoinDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/security/dao/SecurityGroupJoinDaoImpl.java b/server/src/com/cloud/network/security/dao/SecurityGroupJoinDaoImpl.java
index 2237112..019cf2c 100644
--- a/server/src/com/cloud/network/security/dao/SecurityGroupJoinDaoImpl.java
+++ b/server/src/com/cloud/network/security/dao/SecurityGroupJoinDaoImpl.java
@@ -37,6 +37,7 @@ import com.cloud.api.response.SecurityGroupResponse;
 import com.cloud.api.response.SecurityGroupRuleResponse;
 import com.cloud.api.response.UserVmResponse;
 import com.cloud.api.view.vo.DomainRouterJoinVO;
+import com.cloud.api.view.vo.ResourceTagJoinVO;
 import com.cloud.api.view.vo.SecurityGroupJoinVO;
 import com.cloud.dc.DataCenter;
 import com.cloud.network.Network;
@@ -126,29 +127,10 @@ public class SecurityGroupJoinDaoImpl extends GenericDaoBase<SecurityGroupJoinVO
         // update tag information
         Long tag_id = vsg.getTagId();
         if (tag_id != null && tag_id.longValue() > 0) {
-            ResourceTagResponse tag = new ResourceTagResponse();
-            tag.setKey(vsg.getTagKey());
-            tag.setValue(vsg.getTagValue());
-            if (vsg.getTagResourceType() != null) {
-                tag.setResourceType(vsg.getTagResourceType().toString());
+            ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id);
+            if ( vtag != null ){
+                sgResponse.addTag(ApiDBUtils.newResourceTagResponse(vtag, false));
             }
-            tag.setId(vsg.getTagResourceUuid()); // tag resource uuid
-            tag.setCustomer(vsg.getTagCustomer());
-            // TODO: assuming tagAccountId and tagDomainId are the same as VM
-            // accountId and domainId
-            tag.setDomainId(vsg.getTagDomainId());
-            if (vsg.getAccountType() == Account.ACCOUNT_TYPE_PROJECT) {
-                tag.setProjectId(vsg.getProjectId());
-                tag.setProjectName(vsg.getProjectName());
-            } else {
-                tag.setAccountName(vsg.getAccountName());
-            }
-            tag.setDomainId(vsg.getDomainId()); // TODO: pending tag resource
-                                                // response uuid change
-            tag.setDomainName(vsg.getDomainName());
-
-            tag.setObjectName("tag");
-            sgResponse.addTag(tag);
         }
         sgResponse.setObjectName("securitygroup");
 
@@ -194,29 +176,10 @@ public class SecurityGroupJoinDaoImpl extends GenericDaoBase<SecurityGroupJoinVO
         // update tag information
         Long tag_id = vsg.getTagId();
         if (tag_id != null && tag_id.longValue() > 0 ) {
-            ResourceTagResponse tag = new ResourceTagResponse();
-            tag.setKey(vsg.getTagKey());
-            tag.setValue(vsg.getTagValue());
-            if (vsg.getTagResourceType() != null) {
-                tag.setResourceType(vsg.getTagResourceType().toString());
+            ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id);
+            if ( vtag != null ){
+                vsgData.addTag(ApiDBUtils.newResourceTagResponse(vtag, false));
             }
-            tag.setId(vsg.getTagResourceUuid()); // tag resource uuid
-            tag.setCustomer(vsg.getTagCustomer());
-            // TODO: assuming tagAccountId and tagDomainId are the same as VM
-            // accountId and domainId
-            tag.setDomainId(vsg.getTagDomainId());
-            if (vsg.getAccountType() == Account.ACCOUNT_TYPE_PROJECT) {
-                tag.setProjectId(vsg.getProjectId());
-                tag.setProjectName(vsg.getProjectName());
-            } else {
-                tag.setAccountName(vsg.getAccountName());
-            }
-            tag.setDomainId(vsg.getDomainId()); // TODO: pending tag resource
-                                                // response uuid change
-            tag.setDomainName(vsg.getDomainName());
-
-            tag.setObjectName("tag");
-            vsgData.addTag(tag);
         }
         return vsgData;
     }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/acf7afd7/server/src/com/cloud/tags/TaggedResourceManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java
index fba3079..3224bc9 100644
--- a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java
+++ b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java
@@ -27,6 +27,8 @@ import javax.naming.ConfigurationException;
 import org.apache.log4j.Logger;
 
 import org.apache.cloudstack.api.user.tag.command.ListTagsCmd;
+
+import com.cloud.api.view.vo.ResourceTagJoinVO;
 import com.cloud.domain.Domain;
 import com.cloud.event.ActionEvent;
 import com.cloud.event.EventTypes;
@@ -50,6 +52,7 @@ import com.cloud.storage.dao.SnapshotDao;
 import com.cloud.storage.dao.VMTemplateDao;
 import com.cloud.storage.dao.VolumeDao;
 import com.cloud.tags.dao.ResourceTagDao;
+import com.cloud.tags.dao.ResourceTagJoinDao;
 import com.cloud.user.Account;
 import com.cloud.user.AccountManager;
 import com.cloud.user.DomainManager;
@@ -83,6 +86,8 @@ public class TaggedResourceManagerImpl implements TaggedResourceService, Manager
     @Inject
     ResourceTagDao _resourceTagDao;
     @Inject
+    ResourceTagJoinDao _resourceTagJoinDao;
+    @Inject
     IdentityDao _identityDao;
     @Inject
     DomainManager _domainMgr;
@@ -269,7 +274,7 @@ public class TaggedResourceManagerImpl implements TaggedResourceService, Manager
                     _accountMgr.checkAccess(caller, _domainMgr.getDomain(domainId));
                 } else {
                     throw new PermissionDeniedException("Account " + caller + " doesn't have permissions to create tags" +
-                    		" for resource " + key);
+                            " for resource " + key);
                 }
                 
                 String value = tags.get(key);
@@ -322,7 +327,7 @@ public class TaggedResourceManagerImpl implements TaggedResourceService, Manager
     }
 
     @Override
-    public Pair<List<? extends ResourceTag>, Integer> listTags(ListTagsCmd cmd) {
+    public Pair<List<ResourceTagJoinVO>, Integer> listTags(ListTagsCmd cmd) {
         Account caller = UserContext.current().getCaller();
         List<Long> permittedAccounts = new ArrayList<Long>();
         String key = cmd.getKey();
@@ -340,10 +345,10 @@ public class TaggedResourceManagerImpl implements TaggedResourceService, Manager
         Long domainId = domainIdRecursiveListProject.first();
         Boolean isRecursive = domainIdRecursiveListProject.second();
         ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
-        Filter searchFilter = new Filter(ResourceTagVO.class, "resourceType", false, cmd.getStartIndex(), cmd.getPageSizeVal());
+        Filter searchFilter = new Filter(ResourceTagJoinVO.class, "resourceType", false, cmd.getStartIndex(), cmd.getPageSizeVal());
 
-        SearchBuilder<ResourceTagVO> sb = _resourceTagDao.createSearchBuilder();
-        _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
+        SearchBuilder<ResourceTagJoinVO> sb = _resourceTagJoinDao.createSearchBuilder();
+        _accountMgr.buildACLViewSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
 
         sb.and("key", sb.entity().getKey(), SearchCriteria.Op.EQ);
         sb.and("value", sb.entity().getValue(), SearchCriteria.Op.EQ);
@@ -358,8 +363,8 @@ public class TaggedResourceManagerImpl implements TaggedResourceService, Manager
         sb.and("customer", sb.entity().getCustomer(), SearchCriteria.Op.EQ);
 
         // now set the SC criteria...
-        SearchCriteria<ResourceTagVO> sc = sb.create();
-        _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
+        SearchCriteria<ResourceTagJoinVO> sc = sb.create();
+        _accountMgr.buildACLViewSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
 
         if (key != null) {
             sc.setParameters("key", key);
@@ -382,8 +387,8 @@ public class TaggedResourceManagerImpl implements TaggedResourceService, Manager
             sc.setParameters("customer", customerName);
         }
 
-        Pair<List<ResourceTagVO>, Integer> result = _resourceTagDao.searchAndCount(sc, searchFilter);
-        return new Pair<List<? extends ResourceTag>, Integer> (result.first(), result.second());
+        Pair<List<ResourceTagJoinVO>, Integer> result = _resourceTagJoinDao.searchAndCount(sc, searchFilter);
+        return new Pair<List<ResourceTagJoinVO>, Integer> (result.first(), result.second());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/acf7afd7/server/src/com/cloud/tags/dao/ResourceTagJoinDao.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/tags/dao/ResourceTagJoinDao.java b/server/src/com/cloud/tags/dao/ResourceTagJoinDao.java
new file mode 100644
index 0000000..8aa0a16
--- /dev/null
+++ b/server/src/com/cloud/tags/dao/ResourceTagJoinDao.java
@@ -0,0 +1,34 @@
+// 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.tags.dao;
+
+import java.util.List;
+
+import com.cloud.api.response.ResourceTagResponse;
+import com.cloud.api.view.vo.ResourceTagJoinVO;
+import com.cloud.server.ResourceTag;
+import com.cloud.user.Account;
+import com.cloud.utils.db.GenericDao;
+
+public interface ResourceTagJoinDao extends GenericDao<ResourceTagJoinVO, Long> {
+
+    ResourceTagResponse newResourceTagResponse(ResourceTagJoinVO uvo, boolean keyValueOnly );
+
+    ResourceTagJoinVO newResourceTagView(ResourceTag vr);
+
+    List<ResourceTagJoinVO> searchByIds(Long... ids);
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/acf7afd7/server/src/com/cloud/tags/dao/ResourceTagJoinDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/tags/dao/ResourceTagJoinDaoImpl.java b/server/src/com/cloud/tags/dao/ResourceTagJoinDaoImpl.java
new file mode 100644
index 0000000..6593f90
--- /dev/null
+++ b/server/src/com/cloud/tags/dao/ResourceTagJoinDaoImpl.java
@@ -0,0 +1,137 @@
+// 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.tags.dao;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.ejb.Local;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.api.ApiDBUtils;
+import com.cloud.api.ApiResponseHelper;
+import com.cloud.api.response.DomainRouterResponse;
+import com.cloud.api.response.NicResponse;
+import com.cloud.api.response.ResourceTagResponse;
+import com.cloud.api.response.SecurityGroupResponse;
+import com.cloud.api.response.UserVmResponse;
+import com.cloud.api.view.vo.DomainRouterJoinVO;
+import com.cloud.api.view.vo.ResourceTagJoinVO;
+import com.cloud.dc.DataCenter;
+import com.cloud.network.Network;
+import com.cloud.network.Networks.TrafficType;
+import com.cloud.network.router.VirtualRouter;
+import com.cloud.offering.ServiceOffering;
+import com.cloud.projects.Project;
+import com.cloud.server.ResourceTag;
+import com.cloud.user.Account;
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.Pair;
+import com.cloud.utils.db.Attribute;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.JoinBuilder;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.NicProfile;
+
+
+@Local(value={ResourceTagJoinDao.class})
+public class ResourceTagJoinDaoImpl extends GenericDaoBase<ResourceTagJoinVO, Long> implements ResourceTagJoinDao {
+    public static final Logger s_logger = Logger.getLogger(ResourceTagJoinDaoImpl.class);
+
+    private SearchBuilder<ResourceTagJoinVO> vrSearch;
+
+    private SearchBuilder<ResourceTagJoinVO> vrIdSearch;
+
+    protected ResourceTagJoinDaoImpl() {
+
+        vrSearch = createSearchBuilder();
+        vrSearch.and("idIN", vrSearch.entity().getId(), SearchCriteria.Op.IN);
+        vrSearch.done();
+
+        vrIdSearch = createSearchBuilder();
+        vrIdSearch.and("id", vrIdSearch.entity().getId(), SearchCriteria.Op.EQ);
+        vrIdSearch.done();
+
+        this._count = "select count(distinct id) from resource_tag_view WHERE ";
+    }
+
+
+
+
+
+    @Override
+    public ResourceTagResponse newResourceTagResponse(ResourceTagJoinVO resourceTag, boolean keyValueOnly) {
+        ResourceTagResponse response = new ResourceTagResponse();
+        response.setKey(resourceTag.getKey());
+        response.setValue(resourceTag.getValue());
+
+        if (!keyValueOnly) {
+            response.setResourceType(resourceTag.getResourceType().toString());
+            response.setResourceId(resourceTag.getResourceUuid());
+
+            if (resourceTag.getAccountType() == Account.ACCOUNT_TYPE_PROJECT) {
+
+                response.setProjectId(resourceTag.getProjectUuid());
+                response.setProjectName(resourceTag.getProjectName());
+            } else {
+                response.setAccountName(resourceTag.getAccountName());
+            }
+
+            response.setDomainId(resourceTag.getDomainUuid());
+            response.setDomainName(resourceTag.getDomainName());
+
+            response.setCustomer(resourceTag.getCustomer());
+        }
+
+        response.setObjectName("tag");
+
+        return response;
+    }
+
+
+    @Override
+    public List<ResourceTagJoinVO> searchByIds(Long... ids) {
+        SearchCriteria<ResourceTagJoinVO> sc = vrSearch.create();
+        sc.setParameters("idIN", ids);
+        return searchIncludingRemoved(sc, null, null, false);
+    }
+
+
+    @Override
+    public ResourceTagJoinVO newResourceTagView(ResourceTag vr) {
+
+        List<ResourceTagJoinVO> uvList = new ArrayList<ResourceTagJoinVO>();
+        SearchCriteria<ResourceTagJoinVO> sc = vrIdSearch.create();
+        sc.setParameters("id", vr.getId());
+        List<ResourceTagJoinVO> vms = searchIncludingRemoved(sc, null, null, false);
+        assert vms != null && vms.size() == 1 : "No tag found for tag id " + vr.getId();
+        return vms.get(0);
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/acf7afd7/server/src/com/cloud/vm/dao/UserVmJoinDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/dao/UserVmJoinDaoImpl.java b/server/src/com/cloud/vm/dao/UserVmJoinDaoImpl.java
index 63ebb26..742784c 100644
--- a/server/src/com/cloud/vm/dao/UserVmJoinDaoImpl.java
+++ b/server/src/com/cloud/vm/dao/UserVmJoinDaoImpl.java
@@ -36,6 +36,7 @@ import com.cloud.api.response.NicResponse;
 import com.cloud.api.response.ResourceTagResponse;
 import com.cloud.api.response.SecurityGroupResponse;
 import com.cloud.api.response.UserVmResponse;
+import com.cloud.api.view.vo.ResourceTagJoinVO;
 import com.cloud.api.view.vo.UserVmJoinVO;
 import com.cloud.user.Account;
 import com.cloud.uservm.UserVm;
@@ -209,29 +210,10 @@ public class UserVmJoinDaoImpl extends GenericDaoBase<UserVmJoinVO, Long> implem
         // update tag information
         long tag_id = userVm.getTagId();
         if (tag_id > 0) {
-            ResourceTagResponse tag = new ResourceTagResponse();
-            tag.setKey(userVm.getTagKey());
-            tag.setValue(userVm.getTagValue());
-            if (userVm.getTagResourceType() != null) {
-                tag.setResourceType(userVm.getTagResourceType().toString());
+            ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id);
+            if ( vtag != null ){
+                userVmResponse.addTag(ApiDBUtils.newResourceTagResponse(vtag, false));
             }
-            tag.setId(userVm.getTagResourceUuid()); // tag resource uuid
-            tag.setCustomer(userVm.getTagCustomer());
-            // TODO: assuming tagAccountId and tagDomainId are the same as VM
-            // accountId and domainId
-            tag.setDomainId(userVm.getTagDomainId());
-            if (userVm.getAccountType() == Account.ACCOUNT_TYPE_PROJECT) {
-                tag.setProjectId(userVm.getProjectId());
-                tag.setProjectName(userVm.getProjectName());
-            } else {
-                tag.setAccountName(userVm.getAccountName());
-            }
-            tag.setDomainId(userVm.getDomainId()); // TODO: pending tag resource
-                                                // response uuid change
-            tag.setDomainName(userVm.getDomainName());
-
-            tag.setObjectName("tag");
-            userVmResponse.addTag(tag);
         }
         userVmResponse.setObjectName(objectName);
 
@@ -283,29 +265,10 @@ public class UserVmJoinDaoImpl extends GenericDaoBase<UserVmJoinVO, Long> implem
 
         long tag_id = uvo.getTagId();
         if (tag_id > 0) {
-            ResourceTagResponse tag = new ResourceTagResponse();
-            tag.setKey(uvo.getTagKey());
-            tag.setValue(uvo.getTagValue());
-            if (uvo.getTagResourceType() != null) {
-                tag.setResourceType(uvo.getTagResourceType().toString());
+            ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id);
+            if ( vtag != null ){
+                userVmData.addTag(ApiDBUtils.newResourceTagResponse(vtag, false));
             }
-            tag.setId(uvo.getTagResourceUuid()); // tag resource uuid
-            tag.setCustomer(uvo.getTagCustomer());
-            // TODO: assuming tagAccountId and tagDomainId are the same as VM
-            // accountId and domainId
-            tag.setDomainId(uvo.getTagDomainId());
-            if (uvo.getAccountType() == Account.ACCOUNT_TYPE_PROJECT) {
-                tag.setProjectId(uvo.getProjectId());
-                tag.setProjectName(uvo.getProjectName());
-            } else {
-                tag.setAccountName(uvo.getAccountName());
-            }
-            tag.setDomainId(uvo.getDomainId()); // TODO: pending tag resource
-                                                // response uuid change
-            tag.setDomainName(uvo.getDomainName());
-
-            tag.setObjectName("tag");
-            userVmData.addTag(tag);
         }
         return userVmData;
     }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/acf7afd7/setup/db/create-schema.sql
----------------------------------------------------------------------
diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql
index 0141149..3129fd5 100755
--- a/setup/db/create-schema.sql
+++ b/setup/db/create-schema.sql
@@ -2774,3 +2774,31 @@ inner join domain on security_group.domain_id=domain.id
 left join projects on projects.project_account_id = security_group.account_id
 left join resource_tags on resource_tags.resource_id = security_group.id and resource_tags.resource_type = "SecurityGroup"
 left join async_job on async_job.instance_id = security_group.id and async_job.instance_type = "SecurityGroup" and async_job.job_status = 0;
+
+DROP VIEW IF EXISTS `cloud`.`resource_tag_view`;
+CREATE VIEW resource_tag_view AS
+select
+resource_tags.id,
+resource_tags.uuid,
+resource_tags.key,
+resource_tags.value,
+resource_tags.resource_id,
+resource_tags.resource_uuid,
+resource_tags.resource_type,
+resource_tags.customer,
+account.id account_id,
+account.uuid account_uuid,
+account.account_name account_name,
+account.type account_type,
+domain.id domain_id,
+domain.uuid domain_uuid,
+domain.name domain_name,
+domain.path domain_path,
+projects.id project_id,
+projects.uuid project_uuid,
+projects.name project_name
+from resource_tags
+inner join account on resource_tags.account_id=account.id
+inner join domain on resource_tags.domain_id=domain.id
+left join projects on projects.project_account_id = resource_tags.account_id;
+