mirror of https://github.com/apache/cloudstack.git
Now really adding the renamed files!
This commit is contained in:
parent
3d654fdd5e
commit
6257af95ed
|
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ANSI';
|
||||
|
||||
DROP DATABASE IF EXISTS cloudbridge;
|
||||
|
|
@ -10,3 +11,18 @@ GRANT process ON *.* TO `cloud`@`localhost`;
|
|||
GRANT process ON *.* TO `cloud`@`%`;
|
||||
|
||||
COMMIT;
|
||||
=======
|
||||
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ANSI';
|
||||
|
||||
DROP DATABASE IF EXISTS cloudbridge;
|
||||
CREATE DATABASE cloudbridge;
|
||||
|
||||
GRANT ALL ON cloudbridge.* to `cloud`@`localhost` identified by 'cloud';
|
||||
GRANT ALL ON cloudbridge.* to `cloud`@`%` identified by 'cloud';
|
||||
|
||||
GRANT process ON *.* TO `cloud`@`localhost`;
|
||||
GRANT process ON *.* TO `cloud`@`%`;
|
||||
|
||||
COMMIT;
|
||||
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
|
|
|||
|
|
@ -20,7 +20,11 @@ def get_signature(key, url, query):
|
|||
hmac.new(key, '\n'.join(['GET', netloc, path, query]), sha).digest()))
|
||||
|
||||
def get_url(url, api_key, secret_key, action, query):
|
||||
<<<<<<< HEAD
|
||||
amzn_string = 'AWSAccessKeyId=' + api_key + '&Action=' + action + '&SignatureMethod=HmacSHA1'
|
||||
=======
|
||||
amzn_string = 'AWSAccessKeyId=' + api_key + '&CloudAction=' + action + '&SignatureMethod=HmacSHA1'
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
amzn_string += '&SignatureVersion=2&Timestamp='+ datetime.now().isoformat()[:19] +'Z&Version=2010-11-15'
|
||||
query = amzn_string + '&' + query
|
||||
url = url + '?' + query + '&Signature=' + get_signature(secret_key, url, query)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Cloud.com Bridge DB setup script.
|
||||
#
|
||||
|
||||
from getpass import getpass
|
||||
from subprocess import call
|
||||
|
||||
setup_db_dir = '/usr/share/cloud/setup/bridge/db'
|
||||
setup_db_script = 'deploy-db-bridge.sh'
|
||||
|
||||
print 'Welcome to CloudBridge Database setup.'
|
||||
passwd = getpass('Please enter the MySQL password for root@localhost: ')
|
||||
|
||||
call(['/bin/bash', setup_db_script, 'cloud', 'root', passwd], cwd=setup_db_dir)
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
// 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.
|
||||
|
||||
// ============================================================================
|
||||
// catalina.corepolicy - Security Policy Permissions for Tomcat 6
|
||||
//
|
||||
// This file contains a default set of security policies to be enforced (by the
|
||||
// JVM) when Catalina is executed with the "-security" option. In addition
|
||||
// to the permissions granted here, the following additional permissions are
|
||||
// granted to the codebase specific to each web application:
|
||||
//
|
||||
// * Read access to the document root directory
|
||||
//
|
||||
// $Id: catalina.policy 899134 2010-01-14 09:44:28Z rjung $
|
||||
// ============================================================================
|
||||
|
||||
|
||||
// ========== SYSTEM CODE PERMISSIONS =========================================
|
||||
|
||||
|
||||
// These permissions apply to javac
|
||||
grant codeBase "file:${java.home}/lib/-" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
// These permissions apply to all shared system extensions
|
||||
grant codeBase "file:${java.home}/jre/lib/ext/-" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
// These permissions apply to javac when ${java.home] points at $JAVA_HOME/jre
|
||||
grant codeBase "file:${java.home}/../lib/-" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
// These permissions apply to all shared system extensions when
|
||||
// ${java.home} points at $JAVA_HOME/jre
|
||||
grant codeBase "file:${java.home}/lib/ext/-" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
|
||||
// ========== CATALINA CODE PERMISSIONS =======================================
|
||||
|
||||
|
||||
// These permissions apply to the daemon code
|
||||
grant codeBase "file:${catalina.home}/bin/commons-daemon.jar" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
// These permissions apply to the logging API
|
||||
grant codeBase "file:${catalina.home}/bin/tomcat-juli.jar" {
|
||||
permission java.util.PropertyPermission "java.util.logging.config.class", "read";
|
||||
permission java.util.PropertyPermission "java.util.logging.config.file", "read";
|
||||
permission java.io.FilePermission "${java.home}${file.separator}lib${file.separator}logging.properties", "read";
|
||||
permission java.lang.RuntimePermission "shutdownHooks";
|
||||
permission java.io.FilePermission "${catalina.base}${file.separator}conf${file.separator}logging.properties", "read";
|
||||
permission java.util.PropertyPermission "catalina.base", "read";
|
||||
permission java.util.logging.LoggingPermission "control";
|
||||
permission java.io.FilePermission "${catalina.base}${file.separator}logs", "read, write";
|
||||
permission java.io.FilePermission "${catalina.base}${file.separator}logs${file.separator}*", "read, write";
|
||||
permission java.lang.RuntimePermission "getClassLoader";
|
||||
permission java.lang.RuntimePermission "setContextClassLoader";
|
||||
// To enable per context logging configuration, permit read access to the appropriate file.
|
||||
// Be sure that the logging configuration is secure before enabling such access
|
||||
// eg for the examples web application:
|
||||
// permission java.io.FilePermission "${catalina.base}${file.separator}webapps${file.separator}examples${file.separator}WEB-INF${file.separator}classes${file.separator}logging.properties", "read";
|
||||
};
|
||||
|
||||
// These permissions apply to the server startup code
|
||||
grant codeBase "file:${catalina.home}/bin/bootstrap.jar" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
// These permissions apply to the servlet API classes
|
||||
// and those that are shared across all class loaders
|
||||
// located in the "lib" directory
|
||||
grant codeBase "file:${catalina.home}/lib/-" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
|
||||
// ========== WEB APPLICATION PERMISSIONS =====================================
|
||||
|
||||
|
||||
// These permissions are granted by default to all web applications
|
||||
// In addition, a web application will be given a read FilePermission
|
||||
// and JndiPermission for all files and directories in its document root.
|
||||
grant {
|
||||
// Required for JNDI lookup of named JDBC DataSource's and
|
||||
// javamail named MimePart DataSource used to send mail
|
||||
permission java.util.PropertyPermission "java.home", "read";
|
||||
permission java.util.PropertyPermission "java.naming.*", "read";
|
||||
permission java.util.PropertyPermission "javax.sql.*", "read";
|
||||
|
||||
// OS Specific properties to allow read access
|
||||
permission java.util.PropertyPermission "os.name", "read";
|
||||
permission java.util.PropertyPermission "os.version", "read";
|
||||
permission java.util.PropertyPermission "os.arch", "read";
|
||||
permission java.util.PropertyPermission "file.separator", "read";
|
||||
permission java.util.PropertyPermission "path.separator", "read";
|
||||
permission java.util.PropertyPermission "line.separator", "read";
|
||||
|
||||
// JVM properties to allow read access
|
||||
permission java.util.PropertyPermission "java.version", "read";
|
||||
permission java.util.PropertyPermission "java.vendor", "read";
|
||||
permission java.util.PropertyPermission "java.vendor.url", "read";
|
||||
permission java.util.PropertyPermission "java.class.version", "read";
|
||||
permission java.util.PropertyPermission "java.specification.version", "read";
|
||||
permission java.util.PropertyPermission "java.specification.vendor", "read";
|
||||
permission java.util.PropertyPermission "java.specification.name", "read";
|
||||
|
||||
permission java.util.PropertyPermission "java.vm.specification.version", "read";
|
||||
permission java.util.PropertyPermission "java.vm.specification.vendor", "read";
|
||||
permission java.util.PropertyPermission "java.vm.specification.name", "read";
|
||||
permission java.util.PropertyPermission "java.vm.version", "read";
|
||||
permission java.util.PropertyPermission "java.vm.vendor", "read";
|
||||
permission java.util.PropertyPermission "java.vm.name", "read";
|
||||
|
||||
// Required for OpenJMX
|
||||
permission java.lang.RuntimePermission "getAttribute";
|
||||
|
||||
// Allow read of JAXP compliant XML parser debug
|
||||
permission java.util.PropertyPermission "jaxp.debug", "read";
|
||||
|
||||
// Precompiled JSPs need access to these packages.
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.el";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.runtime";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.runtime.*";
|
||||
|
||||
// Precompiled JSPs need access to these system properties.
|
||||
permission java.util.PropertyPermission "org.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER", "read";
|
||||
permission java.util.PropertyPermission "org.apache.el.parser.COERCE_TO_ZERO", "read";
|
||||
};
|
||||
|
||||
|
||||
// You can assign additional permissions to particular web applications by
|
||||
// adding additional "grant" entries here, based on the code base for that
|
||||
// application, /WEB-INF/classes/, or /WEB-INF/lib/ jar files.
|
||||
//
|
||||
// Different permissions can be granted to JSP pages, classes loaded from
|
||||
// the /WEB-INF/classes/ directory, all jar files in the /WEB-INF/lib/
|
||||
// directory, or even to individual jar files in the /WEB-INF/lib/ directory.
|
||||
//
|
||||
// For instance, assume that the standard "examples" application
|
||||
// included a JDBC driver that needed to establish a network connection to the
|
||||
// corresponding database and used the scrape taglib to get the weather from
|
||||
// the NOAA web server. You might create a "grant" entries like this:
|
||||
//
|
||||
// The permissions granted to the context root directory apply to JSP pages.
|
||||
// grant codeBase "file:${catalina.home}/webapps/examples/-" {
|
||||
// permission java.net.SocketPermission "dbhost.mycompany.com:5432", "connect";
|
||||
// permission java.net.SocketPermission "*.noaa.gov:80", "connect";
|
||||
// };
|
||||
//
|
||||
// The permissions granted to the context WEB-INF/classes directory
|
||||
// grant codeBase "file:${catalina.home}/webapps/examples/WEB-INF/classes/-" {
|
||||
// };
|
||||
//
|
||||
// The permission granted to your JDBC driver
|
||||
// grant codeBase "jar:file:${catalina.home}/webapps/examples/WEB-INF/lib/driver.jar!/-" {
|
||||
// permission java.net.SocketPermission "dbhost.mycompany.com:5432", "connect";
|
||||
// };
|
||||
// The permission granted to the scrape taglib
|
||||
// grant codeBase "jar:file:${catalina.home}/webapps/examples/WEB-INF/lib/scrape.jar!/-" {
|
||||
// permission java.net.SocketPermission "*.noaa.gov:80", "connect";
|
||||
// };
|
||||
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
# 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.
|
||||
|
||||
#
|
||||
# List of comma-separated packages that start with or equal this string
|
||||
# will cause a security exception to be thrown when
|
||||
# passed to checkPackageAccess unless the
|
||||
# corresponding RuntimePermission ("accessClassInPackage."+package) has
|
||||
# been granted.
|
||||
package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.,sun.beans.
|
||||
#
|
||||
# List of comma-separated packages that start with or equal this string
|
||||
# will cause a security exception to be thrown when
|
||||
# passed to checkPackageDefinition unless the
|
||||
# corresponding RuntimePermission ("defineClassInPackage."+package) has
|
||||
# been granted.
|
||||
#
|
||||
# by default, no packages are restricted for definition, and none of
|
||||
# the class loaders supplied with the JDK call checkPackageDefinition.
|
||||
#
|
||||
package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.
|
||||
|
||||
#
|
||||
#
|
||||
# List of comma-separated paths defining the contents of the "common"
|
||||
# classloader. Prefixes should be used to define what is the repository type.
|
||||
# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.
|
||||
# If left as blank,the JVM system loader will be used as Catalina's "common"
|
||||
# loader.
|
||||
# Examples:
|
||||
# "foo": Add this folder as a class repository
|
||||
# "foo/*.jar": Add all the JARs of the specified folder as class
|
||||
# repositories
|
||||
# "foo/bar.jar": Add bar.jar as a class repository
|
||||
common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar
|
||||
|
||||
#
|
||||
# List of comma-separated paths defining the contents of the "server"
|
||||
# classloader. Prefixes should be used to define what is the repository type.
|
||||
# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.
|
||||
# If left as blank, the "common" loader will be used as Catalina's "server"
|
||||
# loader.
|
||||
# Examples:
|
||||
# "foo": Add this folder as a class repository
|
||||
# "foo/*.jar": Add all the JARs of the specified folder as class
|
||||
# repositories
|
||||
# "foo/bar.jar": Add bar.jar as a class repository
|
||||
server.loader=
|
||||
|
||||
#
|
||||
# List of comma-separated paths defining the contents of the "shared"
|
||||
# classloader. Prefixes should be used to define what is the repository type.
|
||||
# Path may be relative to the CATALINA_BASE path or absolute. If left as blank,
|
||||
# the "common" loader will be used as Catalina's "shared" loader.
|
||||
# Examples:
|
||||
# "foo": Add this folder as a class repository
|
||||
# "foo/*.jar": Add all the JARs of the specified folder as class
|
||||
# repositories
|
||||
# "foo/bar.jar": Add bar.jar as a class repository
|
||||
# Please note that for single jars, e.g. bar.jar, you need the URL form
|
||||
# starting with file:.
|
||||
shared.loader=
|
||||
|
||||
#
|
||||
# String cache configuration.
|
||||
tomcat.util.buf.StringCache.byte.enabled=true
|
||||
#tomcat.util.buf.StringCache.char.enabled=true
|
||||
#tomcat.util.buf.StringCache.trainThreshold=500000
|
||||
#tomcat.util.buf.StringCache.cacheSize=5000
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
#SYSTEMJARS="@SYSTEMJARS@"
|
||||
#SCP=$(build-classpath $SYSTEMJARS 2>/dev/null) ; if [ $? != 0 ] ; then export SCP="@SYSTEMCLASSPATH@" ; fi
|
||||
#MCP="@MSCLASSPATH@"
|
||||
#DCP="@DEPSCLASSPATH@"
|
||||
CLASSPATH=/usr/share/cloud/bridge/conf
|
||||
export CLASSPATH
|
||||
PATH=/sbin:/usr/sbin:$PATH
|
||||
export PATH
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
components.xml is the configuration file for the VM Ops
|
||||
insertion servers. Someone can quickly pull together an
|
||||
insertion server by selecting the correct adapters to use.
|
||||
|
||||
Here are some places to look for information.
|
||||
- To find out the general functionality that each Manager
|
||||
or Adapter provide, look at the javadoc for the interface
|
||||
that it implements. The interface is usually the
|
||||
"key" attribute in the declaration.
|
||||
- To find specific implementation of each Manager or
|
||||
Adapter, look at the javadoc for the actual class. The
|
||||
class can be found in the <class> element.
|
||||
- To find out the configuration parameters for each Manager
|
||||
or Adapter, look at the javadoc for the actual implementation
|
||||
class. It should be documented in the description of the
|
||||
class.
|
||||
- To know more about the components.xml in general, look for
|
||||
the javadoc for ComponentLocator.java.
|
||||
|
||||
If you found that the Manager or Adapter are not properly
|
||||
documented, please contact the author.
|
||||
-->
|
||||
<components.xml>
|
||||
<interceptor library="com.cloud.configuration.DefaultIntercetorLibrary"/>
|
||||
<management-server class="com.cloud.server.ManagementServerImpl" library="com.cloud.configuration.DefaultComponentLibrary">
|
||||
<adapters key="com.cloud.agent.manager.allocator.HostAllocator">
|
||||
<adapter name="FirstFitRouting" class="com.cloud.agent.manager.allocator.impl.RecreateHostAllocator"/>
|
||||
<!--adapter name="FirstFit" class="com.cloud.agent.manager.allocator.impl.FirstFitAllocator"/-->
|
||||
</adapters>
|
||||
<adapters key="com.cloud.storage.allocator.StoragePoolAllocator">
|
||||
<adapter name="LocalStorage" class="com.cloud.storage.allocator.LocalStoragePoolAllocator"/>
|
||||
<adapter name="Storage" class="com.cloud.storage.allocator.FirstFitStoragePoolAllocator"/>
|
||||
<adapter name="GarbageCollecting" class="com.cloud.storage.allocator.GarbageCollectingStoragePoolAllocator"/>
|
||||
</adapters>
|
||||
<adapters key="com.cloud.agent.manager.allocator.PodAllocator">
|
||||
<adapter name="User First" class="com.cloud.agent.manager.allocator.impl.UserConcentratedAllocator"/>
|
||||
</adapters>
|
||||
<adapters key="com.cloud.consoleproxy.ConsoleProxyAllocator">
|
||||
<adapter name="Balance" class="com.cloud.consoleproxy.ConsoleProxyBalanceAllocator"/>
|
||||
</adapters>
|
||||
<adapters key="com.cloud.network.guru.NetworkGuru">
|
||||
<adapter name="GuestNetworkGuru" class="com.cloud.network.guru.GuestNetworkGuru"/>
|
||||
<adapter name="PublicNetworkGuru" class="com.cloud.network.guru.PublicNetworkGuru"/>
|
||||
<adapter name="PodBasedNetworkGuru" class="com.cloud.network.guru.PodBasedNetworkGuru"/>
|
||||
<adapter name="ControlNetworkGuru" class="com.cloud.network.guru.ControlNetworkGuru"/>
|
||||
<adapter name="DirectNetworkGuru" class="com.cloud.network.guru.DirectNetworkGuru"/>
|
||||
<adapter name="DirectPodBasedNetworkGuru" class="com.cloud.network.guru.DirectPodBasedNetworkGuru"/>
|
||||
</adapters>
|
||||
<adapters key="com.cloud.storage.secondary.SecondaryStorageVmAllocator">
|
||||
<adapter name="Balance" class="com.cloud.storage.secondary.SecondaryStorageVmDefaultAllocator"/>
|
||||
</adapters>
|
||||
<adapters key="com.cloud.network.IpAddrAllocator">
|
||||
<adapter name="Basic" class="com.cloud.network.ExteralIpAddressAllocator"/>
|
||||
</adapters>
|
||||
<adapters key="com.cloud.server.auth.UserAuthenticator">
|
||||
<adapter name="MD5" class="com.cloud.server.auth.MD5UserAuthenticator"/>
|
||||
</adapters>
|
||||
<adapters key="com.cloud.ha.Investigator">
|
||||
<adapter name="SimpleInvestigator" class="com.cloud.ha.CheckOnAgentInvestigator"/>
|
||||
<adapter name="PingInvestigator" class="com.cloud.ha.InvestigatorImpl"/>
|
||||
</adapters>
|
||||
<adapters key="com.cloud.ha.FenceBuilder">
|
||||
<adapter name="StorageFenceBuilder" class="com.cloud.ha.StorageFence"/>
|
||||
</adapters>
|
||||
<adapters key="com.cloud.hypervisor.HypervisorGuru">
|
||||
<adapter name="XenServerGuru" class="com.cloud.hypervisor.XenServerGuru"/>
|
||||
<adapter name="KVMGuru" class="com.cloud.hypervisor.KVMGuru"/>
|
||||
<adapter name="VMwareGuru" class="com.cloud.hypervisor.VMwareGuru"/>
|
||||
</adapters>
|
||||
<adapters key="com.cloud.resource.Discoverer">
|
||||
<adapter name="XCP Agent" class="com.cloud.hypervisor.xen.discoverer.XcpServerDiscoverer"/>
|
||||
<adapter name="SecondaryStorage" class="com.cloud.storage.secondary.SecondaryStorageDiscoverer"/>
|
||||
<adapter name="KVM Agent" class="com.cloud.hypervisor.kvm.discoverer.KvmServerDiscoverer"/>
|
||||
</adapters>
|
||||
<adapters key="com.cloud.deploy.DeploymentPlanner">
|
||||
<adapter name="First Fit" class="com.cloud.deploy.FirstFitPlanner"/>
|
||||
</adapters>
|
||||
<adapters key="com.cloud.utils.fsm.StateListener">
|
||||
<adapter name="VMStateListener" class="com.cloud.stateListener.VMStateListener"/>
|
||||
</adapters>
|
||||
<adapters key="com.cloud.network.element.NetworkElement">
|
||||
<adapter name="DomainRouter" class="com.cloud.network.element.VirtualRouterElement"/>
|
||||
<adapter name="Dhcp" class="com.cloud.network.element.DhcpElement"/>
|
||||
</adapters>
|
||||
<adapters key="com.cloud.acl.SecurityChecker">
|
||||
<adapter name="DomainChecker" class="com.cloud.acl.DomainChecker"/>
|
||||
</adapters>
|
||||
</management-server>
|
||||
|
||||
<configuration-server class="com.cloud.server.ConfigurationServerImpl">
|
||||
<dao name="Configuration configuration server" class="com.cloud.configuration.dao.ConfigurationDaoImpl" singleton="false">
|
||||
<param name="premium">false</param>
|
||||
</dao>
|
||||
<dao name="Snapshot policy defaults" class="com.cloud.storage.dao.SnapshotPolicyDaoImpl" singleton="false"/>
|
||||
<dao name="DiskOffering configuration server" class="com.cloud.storage.dao.DiskOfferingDaoImpl" singleton="false"/>
|
||||
<dao name="ServiceOffering configuration server" class="com.cloud.service.dao.ServiceOfferingDaoImpl" singleton="false"/>
|
||||
<dao name="host zone configuration server" class="com.cloud.dc.dao.DataCenterDaoImpl" singleton="false"/>
|
||||
<dao name="host pod configuration server" class="com.cloud.dc.dao.HostPodDaoImpl" singleton="false"/>
|
||||
<dao name="DomainDao" class="com.cloud.domain.dao.DomainDaoImpl" singleton="false"/>
|
||||
<dao name="NetworkOfferingDao" class="com.cloud.offerings.dao.NetworkOfferingDaoImpl" singleton="false"/>
|
||||
<dao name="DataCenterDao" class="com.cloud.dc.dao.DataCenterDaoImpl" singleton="false"/>
|
||||
<dao name="NetworkDao" class="com.cloud.network.dao.NetworkDaoImpl" singleton="false"/>
|
||||
<dao name="IpAddressDao" class="com.cloud.network.dao.IPAddressDaoImpl" singleton="false"/>
|
||||
<dao name="VlanDao" class="com.cloud.dc.dao.VlanDaoImpl" singleton="false"/>
|
||||
</configuration-server>
|
||||
</components.xml>
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<!-- The contents of this file will be loaded for each web application -->
|
||||
<Context allowLinking="true">
|
||||
|
||||
<!-- Default set of monitored resources -->
|
||||
<WatchedResource>WEB-INF/web.xml</WatchedResource>
|
||||
|
||||
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
|
||||
<!--
|
||||
<Manager pathname="" />
|
||||
-->
|
||||
|
||||
<!-- Uncomment this to enable Comet connection tacking (provides events
|
||||
on session expiration as well as webapp lifecycle) -->
|
||||
<!--
|
||||
<Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
|
||||
-->
|
||||
|
||||
</Context>
|
||||
|
|
@ -0,0 +1,527 @@
|
|||
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="ehcache.xsd">
|
||||
|
||||
<!--
|
||||
CacheManager Configuration
|
||||
==========================
|
||||
An ehcache.xml corresponds to a single CacheManager.
|
||||
|
||||
See instructions below or the ehcache schema (ehcache.xsd) on how to configure.
|
||||
|
||||
System property tokens can be specified in this file which are replaced when the configuration is loaded.
|
||||
For example multicastGroupPort=${multicastGroupPort} can be replaced with the System property either
|
||||
from an environment variable or a system property specified with a command line switch such as
|
||||
-DmulticastGroupPort=4446.
|
||||
|
||||
DiskStore configuration
|
||||
=======================
|
||||
|
||||
The diskStore element is optional. To turn off disk store path creation, comment out the diskStore
|
||||
element below.
|
||||
|
||||
Configure it if you have overflowToDisk or diskPersistent enabled for any cache.
|
||||
|
||||
If it is not configured, and a cache is created which requires a disk store, a warning will be
|
||||
issued and java.io.tmpdir will automatically be used.
|
||||
|
||||
diskStore has only one attribute - "path". It is the path to the directory where
|
||||
.data and .index files will be created.
|
||||
|
||||
If the path is one of the following Java System Property it is replaced by its value in the
|
||||
running VM. For backward compatibility these are not specified without being enclosed in the ${token}
|
||||
replacement syntax.
|
||||
|
||||
The following properties are translated:
|
||||
* user.home - User's home directory
|
||||
* user.dir - User's current working directory
|
||||
* java.io.tmpdir - Default temp file path
|
||||
* ehcache.disk.store.dir - A system property you would normally specify on the command line
|
||||
e.g. java -Dehcache.disk.store.dir=/u01/myapp/diskdir ...
|
||||
|
||||
Subdirectories can be specified below the property e.g. java.io.tmpdir/one
|
||||
-->
|
||||
<!-- diskStore path="java.io.tmpdir"/ -->
|
||||
|
||||
<!--
|
||||
CacheManagerEventListener
|
||||
=========================
|
||||
Specifies a CacheManagerEventListenerFactory, be used to create a CacheManagerPeerProvider,
|
||||
which is notified when Caches are added or removed from the CacheManager.
|
||||
|
||||
The attributes of CacheManagerEventListenerFactory are:
|
||||
* class - a fully qualified factory class name
|
||||
* properties - comma separated properties having meaning only to the factory.
|
||||
|
||||
Sets the fully qualified class name to be registered as the CacheManager event listener.
|
||||
|
||||
The events include:
|
||||
* adding a Cache
|
||||
* removing a Cache
|
||||
|
||||
Callbacks to listener methods are synchronous and unsynchronized. It is the responsibility
|
||||
of the implementer to safely handle the potential performance and thread safety issues
|
||||
depending on what their listener is doing.
|
||||
|
||||
If no class is specified, no listener is created. There is no default.
|
||||
-->
|
||||
<cacheManagerEventListenerFactory class="" properties=""/>
|
||||
|
||||
|
||||
<!--
|
||||
CacheManagerPeerProvider
|
||||
========================
|
||||
(Enable for distributed operation)
|
||||
|
||||
Specifies a CacheManagerPeerProviderFactory which will be used to create a
|
||||
CacheManagerPeerProvider, which discovers other CacheManagers in the cluster.
|
||||
|
||||
The attributes of cacheManagerPeerProviderFactory are:
|
||||
* class - a fully qualified factory class name
|
||||
* properties - comma separated properties having meaning only to the factory.
|
||||
|
||||
Ehcache comes with a built-in RMI-based distribution system with two means of discovery of
|
||||
CacheManager peers participating in the cluster:
|
||||
* automatic, using a multicast group. This one automatically discovers peers and detects
|
||||
changes such as peers entering and leaving the group
|
||||
* manual, using manual rmiURL configuration. A hardcoded list of peers is provided at
|
||||
configuration time.
|
||||
|
||||
Configuring Automatic Discovery:
|
||||
Automatic discovery is configured as per the following example:
|
||||
<cacheManagerPeerProviderFactory
|
||||
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
|
||||
properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1,
|
||||
multicastGroupPort=4446, timeToLive=32"/>
|
||||
|
||||
Valid properties are:
|
||||
* peerDiscovery (mandatory) - specify "automatic"
|
||||
* multicastGroupAddress (mandatory) - specify a valid multicast group address
|
||||
* multicastGroupPort (mandatory) - specify a dedicated port for the multicast heartbeat
|
||||
traffic
|
||||
* timeToLive - specify a value between 0 and 255 which determines how far the packets will
|
||||
propagate.
|
||||
|
||||
By convention, the restrictions are:
|
||||
0 - the same host
|
||||
1 - the same subnet
|
||||
32 - the same site
|
||||
64 - the same region
|
||||
128 - the same continent
|
||||
255 - unrestricted
|
||||
|
||||
Configuring Manual Discovery:
|
||||
Manual discovery is configured as per the following example:
|
||||
<cacheManagerPeerProviderFactory class=
|
||||
"net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
|
||||
properties="peerDiscovery=manual,
|
||||
rmiUrls=//server1:40000/sampleCache1|//server2:40000/sampleCache1
|
||||
| //server1:40000/sampleCache2|//server2:40000/sampleCache2"
|
||||
propertySeparator="," />
|
||||
|
||||
Valid properties are:
|
||||
* peerDiscovery (mandatory) - specify "manual"
|
||||
* rmiUrls (mandatory) - specify a pipe separated list of rmiUrls, in the form
|
||||
//hostname:port
|
||||
|
||||
The hostname is the hostname of the remote CacheManager peer. The port is the listening
|
||||
port of the RMICacheManagerPeerListener of the remote CacheManager peer.
|
||||
|
||||
Configuring JGroups replication:
|
||||
<cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory"
|
||||
properties="connect=UDP(mcast_addr=231.12.21.132;mcast_port=45566;ip_ttl=32;
|
||||
mcast_send_buf_size=150000;mcast_recv_buf_size=80000):
|
||||
PING(timeout=2000;num_initial_members=6):
|
||||
MERGE2(min_interval=5000;max_interval=10000):
|
||||
FD_SOCK:VERIFY_SUSPECT(timeout=1500):
|
||||
pbcast.NAKACK(gc_lag=10;retransmit_timeout=3000):
|
||||
UNICAST(timeout=5000):
|
||||
pbcast.STABLE(desired_avg_gossip=20000):
|
||||
FRAG:
|
||||
pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;print_local_addr=false)"
|
||||
propertySeparator="::"
|
||||
/>
|
||||
The only property necessay is the connect String used by jgroups to configure itself. Refer to the Jgroups documentation for explanation
|
||||
of all the protocols. The example above uses UDP multicast. If the connect property is not specified the default JGroups connection will be
|
||||
used.
|
||||
|
||||
-->
|
||||
<cacheManagerPeerProviderFactory
|
||||
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
|
||||
properties="peerDiscovery=automatic,
|
||||
multicastGroupAddress=230.0.0.1,
|
||||
multicastGroupPort=4446, timeToLive=1"
|
||||
propertySeparator=","
|
||||
/>
|
||||
|
||||
|
||||
<!--
|
||||
CacheManagerPeerListener
|
||||
========================
|
||||
(Enable for distributed operation)
|
||||
|
||||
Specifies a CacheManagerPeerListenerFactory which will be used to create a
|
||||
CacheManagerPeerListener, which
|
||||
listens for messages from cache replicators participating in the cluster.
|
||||
|
||||
The attributes of cacheManagerPeerListenerFactory are:
|
||||
class - a fully qualified factory class name
|
||||
properties - comma separated properties having meaning only to the factory.
|
||||
|
||||
Ehcache comes with a built-in RMI-based distribution system. The listener component is
|
||||
RMICacheManagerPeerListener which is configured using
|
||||
RMICacheManagerPeerListenerFactory. It is configured as per the following example:
|
||||
|
||||
<cacheManagerPeerListenerFactory
|
||||
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
|
||||
properties="hostName=fully_qualified_hostname_or_ip,
|
||||
port=40001,
|
||||
socketTimeoutMillis=120000"
|
||||
propertySeparator="," />
|
||||
|
||||
All properties are optional. They are:
|
||||
* hostName - the hostName of the host the listener is running on. Specify
|
||||
where the host is multihomed and you want to control the interface over which cluster
|
||||
messages are received. Defaults to the host name of the default interface if not
|
||||
specified.
|
||||
* port - the port the RMI Registry listener listens on. This defaults to a free port if not specified.
|
||||
* remoteObjectPort - the port number on which the remote objects bound in the registry receive calls.
|
||||
This defaults to a free port if not specified.
|
||||
* socketTimeoutMillis - the number of ms client sockets will stay open when sending
|
||||
messages to the listener. This should be long enough for the slowest message.
|
||||
If not specified it defaults 120000ms.
|
||||
|
||||
-->
|
||||
<cacheManagerPeerListenerFactory
|
||||
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"/>
|
||||
|
||||
|
||||
<!--
|
||||
Cache configuration
|
||||
===================
|
||||
|
||||
The following attributes are required.
|
||||
|
||||
name:
|
||||
Sets the name of the cache. This is used to identify the cache. It must be unique.
|
||||
|
||||
maxElementsInMemory:
|
||||
Sets the maximum number of objects that will be created in memory
|
||||
|
||||
maxElementsOnDisk:
|
||||
Sets the maximum number of objects that will be maintained in the DiskStore
|
||||
The default value is zero, meaning unlimited.
|
||||
|
||||
eternal:
|
||||
Sets whether elements are eternal. If eternal, timeouts are ignored and the
|
||||
element is never expired.
|
||||
|
||||
overflowToDisk:
|
||||
Sets whether elements can overflow to disk when the memory store
|
||||
has reached the maxInMemory limit.
|
||||
|
||||
The following attributes and elements are optional.
|
||||
|
||||
timeToIdleSeconds:
|
||||
Sets the time to idle for an element before it expires.
|
||||
i.e. The maximum amount of time between accesses before an element expires
|
||||
Is only used if the element is not eternal.
|
||||
Optional attribute. A value of 0 means that an Element can idle for infinity.
|
||||
The default value is 0.
|
||||
|
||||
timeToLiveSeconds:
|
||||
Sets the time to live for an element before it expires.
|
||||
i.e. The maximum time between creation time and when an element expires.
|
||||
Is only used if the element is not eternal.
|
||||
Optional attribute. A value of 0 means that and Element can live for infinity.
|
||||
The default value is 0.
|
||||
|
||||
diskPersistent:
|
||||
Whether the disk store persists between restarts of the Virtual Machine.
|
||||
The default value is false.
|
||||
|
||||
diskExpiryThreadIntervalSeconds:
|
||||
The number of seconds between runs of the disk expiry thread. The default value
|
||||
is 120 seconds.
|
||||
|
||||
diskSpoolBufferSizeMB:
|
||||
This is the size to allocate the DiskStore for a spool buffer. Writes are made
|
||||
to this area and then asynchronously written to disk. The default size is 30MB.
|
||||
Each spool buffer is used only by its cache. If you get OutOfMemory errors consider
|
||||
lowering this value. To improve DiskStore performance consider increasing it. Trace level
|
||||
logging in the DiskStore will show if put back ups are occurring.
|
||||
|
||||
memoryStoreEvictionPolicy:
|
||||
Policy would be enforced upon reaching the maxElementsInMemory limit. Default
|
||||
policy is Least Recently Used (specified as LRU). Other policies available -
|
||||
First In First Out (specified as FIFO) and Less Frequently Used
|
||||
(specified as LFU)
|
||||
|
||||
Cache elements can also contain sub elements which take the same format of a factory class
|
||||
and properties. Defined sub-elements are:
|
||||
|
||||
* cacheEventListenerFactory - Enables registration of listeners for cache events, such as
|
||||
put, remove, update, and expire.
|
||||
|
||||
* bootstrapCacheLoaderFactory - Specifies a BootstrapCacheLoader, which is called by a
|
||||
cache on initialisation to prepopulate itself.
|
||||
|
||||
* cacheExtensionFactory - Specifies a CacheExtension, a generic mechansim to tie a class
|
||||
which holds a reference to a cache to the cache lifecycle.
|
||||
|
||||
* cacheExceptionHandlerFactory - Specifies a CacheExceptionHandler, which is called when
|
||||
cache exceptions occur.
|
||||
|
||||
* cacheLoaderFactory - Specifies a CacheLoader, which can be used both asynchronously and
|
||||
synchronously to load objects into a cache.
|
||||
|
||||
RMI Cache Replication
|
||||
|
||||
Each cache that will be distributed needs to set a cache event listener which replicates
|
||||
messages to the other CacheManager peers. For the built-in RMI implementation this is done
|
||||
by adding a cacheEventListenerFactory element of type RMICacheReplicatorFactory to each
|
||||
distributed cache's configuration as per the following example:
|
||||
|
||||
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
|
||||
properties="replicateAsynchronously=true,
|
||||
replicatePuts=true,
|
||||
replicateUpdates=true,
|
||||
replicateUpdatesViaCopy=true,
|
||||
replicateRemovals=true
|
||||
asynchronousReplicationIntervalMillis=<number of milliseconds"
|
||||
propertySeparator="," />
|
||||
|
||||
The RMICacheReplicatorFactory recognises the following properties:
|
||||
|
||||
* replicatePuts=true|false - whether new elements placed in a cache are
|
||||
replicated to others. Defaults to true.
|
||||
|
||||
* replicateUpdates=true|false - whether new elements which override an
|
||||
element already existing with the same key are replicated. Defaults to true.
|
||||
|
||||
* replicateRemovals=true - whether element removals are replicated. Defaults to true.
|
||||
|
||||
* replicateAsynchronously=true | false - whether replications are
|
||||
asynchronous (true) or synchronous (false). Defaults to true.
|
||||
|
||||
* replicateUpdatesViaCopy=true | false - whether the new elements are
|
||||
copied to other caches (true), or whether a remove message is sent. Defaults to true.
|
||||
|
||||
* asynchronousReplicationIntervalMillis=<number of milliseconds> - The asynchronous
|
||||
replicator runs at a set interval of milliseconds. The default is 1000. The minimum
|
||||
is 10. This property is only applicable if replicateAsynchronously=true
|
||||
|
||||
|
||||
For the Jgroups replication this is done with:
|
||||
<cacheEventListenerFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"
|
||||
properties="replicateAsynchronously=true, replicatePuts=true,
|
||||
replicateUpdates=true, replicateUpdatesViaCopy=false,
|
||||
replicateRemovals=true,asynchronousReplicationIntervalMillis=1000"/>
|
||||
This listener supports the same property than the RMICacheReplicationFactory.
|
||||
|
||||
Cluster Bootstrapping
|
||||
|
||||
The RMIBootstrapCacheLoader bootstraps caches in clusters where RMICacheReplicators are
|
||||
used. It is configured as per the following example:
|
||||
|
||||
<bootstrapCacheLoaderFactory
|
||||
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
|
||||
properties="bootstrapAsynchronously=true, maximumChunkSizeBytes=5000000"
|
||||
propertySeparator="," />
|
||||
|
||||
The RMIBootstrapCacheLoaderFactory recognises the following optional properties:
|
||||
|
||||
* bootstrapAsynchronously=true|false - whether the bootstrap happens in the background
|
||||
after the cache has started. If false, bootstrapping must complete before the cache is
|
||||
made available. The default value is true.
|
||||
|
||||
* maximumChunkSizeBytes=<integer> - Caches can potentially be very large, larger than the
|
||||
memory limits of the VM. This property allows the bootstraper to fetched elements in
|
||||
chunks. The default chunk size is 5000000 (5MB).
|
||||
|
||||
|
||||
Cache Exception Handling
|
||||
|
||||
By default, most cache operations will propagate a runtime CacheException on failure. An
|
||||
interceptor, using a dynamic proxy, may be configured so that a CacheExceptionHandler can
|
||||
be configured to intercept Exceptions. Errors are not intercepted.
|
||||
|
||||
It is configured as per the following example:
|
||||
|
||||
<cacheExceptionHandlerFactory class="com.example.ExampleExceptionHandlerFactory"
|
||||
properties="logLevel=FINE"/>
|
||||
|
||||
Caches with ExceptionHandling configured are not of type Cache, but are of type Ehcache only,
|
||||
and are not available using CacheManager.getCache(), but using CacheManager.getEhcache().
|
||||
|
||||
|
||||
Cache Loader
|
||||
|
||||
A default CacheLoader may be set which loads objects into the cache through asynchronous and
|
||||
synchronous methods on Cache. This is different to the bootstrap cache loader, which is used
|
||||
only in distributed caching.
|
||||
|
||||
It is configured as per the following example:
|
||||
|
||||
<cacheLoaderFactory class="com.example.ExampleCacheLoaderFactory"
|
||||
properties="type=int,startCounter=10"/>
|
||||
|
||||
Cache Extension
|
||||
|
||||
CacheExtensions are a general purpose mechanism to allow generic extensions to a Cache.
|
||||
CacheExtensions are tied into the Cache lifecycle.
|
||||
|
||||
CacheExtensions are created using the CacheExtensionFactory which has a
|
||||
<code>createCacheCacheExtension()</code> method which takes as a parameter a
|
||||
Cache and properties. It can thus call back into any public method on Cache, including, of
|
||||
course, the load methods.
|
||||
|
||||
Extensions are added as per the following example:
|
||||
|
||||
<cacheExtensionFactory class="com.example.FileWatchingCacheRefresherExtensionFactory"
|
||||
properties="refreshIntervalMillis=18000, loaderTimeout=3000,
|
||||
flushPeriod=whatever, someOtherProperty=someValue ..."/>
|
||||
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
Mandatory Default Cache configuration. These settings will be applied to caches
|
||||
created programmtically using CacheManager.add(String cacheName).
|
||||
|
||||
The defaultCache has an implicit name "default" which is a reserved cache name.
|
||||
-->
|
||||
<defaultCache
|
||||
maxElementsInMemory="10000"
|
||||
eternal="false"
|
||||
timeToIdleSeconds="120"
|
||||
timeToLiveSeconds="120"
|
||||
overflowToDisk="false"
|
||||
diskSpoolBufferSizeMB="30"
|
||||
maxElementsOnDisk="10000000"
|
||||
diskPersistent="false"
|
||||
diskExpiryThreadIntervalSeconds="120"
|
||||
memoryStoreEvictionPolicy="LRU"
|
||||
/>
|
||||
|
||||
<!--
|
||||
Sample caches. Following are some example caches. Remove these before use.
|
||||
-->
|
||||
|
||||
<!--
|
||||
Sample cache named sampleCache1
|
||||
This cache contains a maximum in memory of 10000 elements, and will expire
|
||||
an element if it is idle for more than 5 minutes and lives for more than
|
||||
10 minutes.
|
||||
|
||||
If there are more than 10000 elements it will overflow to the
|
||||
disk cache, which in this configuration will go to wherever java.io.tmp is
|
||||
defined on your system. On a standard Linux system this will be /tmp"
|
||||
-->
|
||||
<!--
|
||||
<cache name="sampleCache1"
|
||||
maxElementsInMemory="10000"
|
||||
maxElementsOnDisk="1000"
|
||||
eternal="false"
|
||||
overflowToDisk="true"
|
||||
diskSpoolBufferSizeMB="20"
|
||||
timeToIdleSeconds="300"
|
||||
timeToLiveSeconds="600"
|
||||
memoryStoreEvictionPolicy="LFU"
|
||||
/>
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
Sample cache named sampleCache2
|
||||
This cache has a maximum of 1000 elements in memory. There is no overflow to disk, so 1000
|
||||
is also the maximum cache size. Note that when a cache is eternal, timeToLive and
|
||||
timeToIdle are not used and do not need to be specified.
|
||||
-->
|
||||
<!--
|
||||
<cache name="sampleCache2"
|
||||
maxElementsInMemory="1000"
|
||||
eternal="true"
|
||||
overflowToDisk="false"
|
||||
memoryStoreEvictionPolicy="FIFO"
|
||||
/>
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
Sample cache named sampleCache3. This cache overflows to disk. The disk store is
|
||||
persistent between cache and VM restarts. The disk expiry thread interval is set to 10
|
||||
minutes, overriding the default of 2 minutes.
|
||||
-->
|
||||
<!--
|
||||
<cache name="sampleCache3"
|
||||
maxElementsInMemory="500"
|
||||
eternal="false"
|
||||
overflowToDisk="true"
|
||||
timeToIdleSeconds="300"
|
||||
timeToLiveSeconds="600"
|
||||
diskPersistent="true"
|
||||
diskExpiryThreadIntervalSeconds="1"
|
||||
memoryStoreEvictionPolicy="LFU"
|
||||
/>
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
Sample distributed cache named sampleDistributedCache1.
|
||||
This cache replicates using defaults.
|
||||
It also bootstraps from the cluster, using default properties.
|
||||
-->
|
||||
<!--
|
||||
<cache name="sampleDistributedCache1"
|
||||
maxElementsInMemory="10"
|
||||
eternal="false"
|
||||
timeToIdleSeconds="100"
|
||||
timeToLiveSeconds="100"
|
||||
overflowToDisk="false">
|
||||
<cacheEventListenerFactory
|
||||
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
|
||||
<bootstrapCacheLoaderFactory
|
||||
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"/>
|
||||
</cache>
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
Sample distributed cache named sampleDistributedCache2.
|
||||
This cache replicates using specific properties.
|
||||
It only replicates updates and does so synchronously via copy
|
||||
-->
|
||||
<!--
|
||||
<cache name="sampleDistributedCache2"
|
||||
maxElementsInMemory="10"
|
||||
eternal="false"
|
||||
timeToIdleSeconds="100"
|
||||
timeToLiveSeconds="100"
|
||||
overflowToDisk="false">
|
||||
<cacheEventListenerFactory
|
||||
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
|
||||
properties="replicateAsynchronously=false, replicatePuts=false,
|
||||
replicateUpdates=true, replicateUpdatesViaCopy=true,
|
||||
replicateRemovals=false"/>
|
||||
</cache>
|
||||
-->
|
||||
|
||||
<!--
|
||||
Sample distributed cache named sampleDistributedCache3.
|
||||
This cache replicates using defaults except that the asynchronous replication
|
||||
interval is set to 200ms.
|
||||
-->
|
||||
<!--
|
||||
<cache name="sampleDistributedCache3"
|
||||
maxElementsInMemory="10"
|
||||
eternal="false"
|
||||
timeToIdleSeconds="100"
|
||||
timeToLiveSeconds="100"
|
||||
overflowToDisk="false">
|
||||
<cacheEventListenerFactory
|
||||
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
|
||||
properties="asynchronousReplicationIntervalMillis=200"/>
|
||||
</cache>
|
||||
-->
|
||||
|
||||
</ehcache>
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
# 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.
|
||||
|
||||
handlers = 1catalina.org.apache.juli.FileHandler, 2localhost.org.apache.juli.FileHandler, 3manager.org.apache.juli.FileHandler, 4host-manager.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
|
||||
|
||||
.handlers = 1catalina.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
|
||||
|
||||
############################################################
|
||||
# Handler specific properties.
|
||||
# Describes specific configuration info for Handlers.
|
||||
############################################################
|
||||
|
||||
1catalina.org.apache.juli.FileHandler.level = FINE
|
||||
1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
|
||||
1catalina.org.apache.juli.FileHandler.prefix = catalina.
|
||||
|
||||
2localhost.org.apache.juli.FileHandler.level = FINE
|
||||
2localhost.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
|
||||
2localhost.org.apache.juli.FileHandler.prefix = localhost.
|
||||
|
||||
3manager.org.apache.juli.FileHandler.level = FINE
|
||||
3manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
|
||||
3manager.org.apache.juli.FileHandler.prefix = manager.
|
||||
|
||||
4host-manager.org.apache.juli.FileHandler.level = FINE
|
||||
4host-manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
|
||||
4host-manager.org.apache.juli.FileHandler.prefix = host-manager.
|
||||
|
||||
java.util.logging.ConsoleHandler.level = FINE
|
||||
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
|
||||
|
||||
|
||||
############################################################
|
||||
# Facility specific properties.
|
||||
# Provides extra control for each logger.
|
||||
############################################################
|
||||
|
||||
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO
|
||||
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = 2localhost.org.apache.juli.FileHandler
|
||||
|
||||
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO
|
||||
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = 3manager.org.apache.juli.FileHandler
|
||||
|
||||
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].level = INFO
|
||||
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].handlers = 4host-manager.org.apache.juli.FileHandler
|
||||
|
||||
# For example, set the com.xyz.foo logger to only log SEVERE
|
||||
# messages:
|
||||
#org.apache.catalina.startup.ContextConfig.level = FINE
|
||||
#org.apache.catalina.startup.HostConfig.level = FINE
|
||||
#org.apache.catalina.session.ManagerBase.level = FINE
|
||||
#org.apache.catalina.core.AprLifecycleListener.level=FINE
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<!-- Note: A "Server" is not itself a "Container", so you may not
|
||||
define subcomponents such as "Valves" at this level.
|
||||
Documentation at /docs/config/server.html
|
||||
-->
|
||||
<Server port="8005" shutdown="SHUTDOWN">
|
||||
|
||||
<!--APR library loader. Documentation at /docs/apr.html -->
|
||||
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
|
||||
<!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
|
||||
<Listener className="org.apache.catalina.core.JasperListener" />
|
||||
<!-- JMX Support for the Tomcat server. Documentation at /docs/non-existent.html -->
|
||||
<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
|
||||
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
|
||||
|
||||
<!-- Global JNDI resources
|
||||
Documentation at /docs/jndi-resources-howto.html
|
||||
-->
|
||||
<GlobalNamingResources>
|
||||
<!-- Editable user database that can also be used by
|
||||
UserDatabaseRealm to authenticate users
|
||||
-->
|
||||
<Resource name="UserDatabase" auth="Container"
|
||||
type="org.apache.catalina.UserDatabase"
|
||||
description="User database that can be updated and saved"
|
||||
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
|
||||
pathname="conf/tomcat-users.xml" />
|
||||
</GlobalNamingResources>
|
||||
|
||||
<!-- A "Service" is a collection of one or more "Connectors" that share
|
||||
a single "Container" Note: A "Service" is not itself a "Container",
|
||||
so you may not define subcomponents such as "Valves" at this level.
|
||||
Documentation at /docs/config/service.html
|
||||
-->
|
||||
<Service name="Catalina">
|
||||
|
||||
<!--The connectors can use a shared executor, you can define one or more named thread pools-->
|
||||
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
|
||||
maxThreads="150" minSpareThreads="25"/>
|
||||
|
||||
|
||||
<!-- A "Connector" represents an endpoint by which requests are received
|
||||
and responses are returned. Documentation at :
|
||||
Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)
|
||||
Java AJP Connector: /docs/config/ajp.html
|
||||
APR (HTTP/AJP) Connector: /docs/apr.html
|
||||
Define a non-SSL HTTP/1.1 Connector on port 8080
|
||||
-->
|
||||
<!--
|
||||
<Connector port="8080" protocol="HTTP/1.1"
|
||||
connectionTimeout="20000"
|
||||
redirectPort="8443" />
|
||||
-->
|
||||
<!-- A "Connector" using the shared thread pool-->
|
||||
<Connector executor="tomcatThreadPool"
|
||||
port="8090" protocol="org.apache.coyote.http11.Http11NioProtocol"
|
||||
connectionTimeout="20000" disableUploadTimeout="true"
|
||||
acceptCount="150" enableLookups="false" maxThreads="150"
|
||||
maxHttpHeaderSize="8192" redirectPort="8443" />
|
||||
<!-- Define a SSL HTTP/1.1 Connector on port 8443
|
||||
This connector uses the JSSE configuration, when using APR, the
|
||||
connector should be using the OpenSSL style configuration
|
||||
described in the APR documentation -->
|
||||
<!--
|
||||
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
|
||||
maxThreads="150" scheme="https" secure="true"
|
||||
clientAuth="false" sslProtocol="TLS"
|
||||
keystoreType="PKCS12"
|
||||
keystoreFile="conf\cloud-localhost.pk12"
|
||||
keystorePass="password"
|
||||
/>
|
||||
-->
|
||||
|
||||
<!-- Define an AJP 1.3 Connector on port 20400 -->
|
||||
<Connector port="20400" protocol="AJP/1.3" redirectPort="8443" />
|
||||
|
||||
|
||||
<!-- An Engine represents the entry point (within Catalina) that processes
|
||||
every request. The Engine implementation for Tomcat stand alone
|
||||
analyzes the HTTP headers included with the request, and passes them
|
||||
on to the appropriate Host (virtual host).
|
||||
Documentation at /docs/config/engine.html -->
|
||||
|
||||
<!-- You should set jvmRoute to support load-balancing via AJP ie :
|
||||
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
|
||||
-->
|
||||
<Engine name="Catalina" defaultHost="localhost">
|
||||
|
||||
<!--For clustering, please take a look at documentation at:
|
||||
/docs/cluster-howto.html (simple how to)
|
||||
/docs/config/cluster.html (reference documentation) -->
|
||||
<!--
|
||||
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
|
||||
-->
|
||||
|
||||
<!-- The request dumper valve dumps useful debugging information about
|
||||
the request and response data received and sent by Tomcat.
|
||||
Documentation at: /docs/config/valve.html -->
|
||||
<!--
|
||||
<Valve className="org.apache.catalina.valves.RequestDumperValve"/>
|
||||
-->
|
||||
|
||||
<!-- This Realm uses the UserDatabase configured in the global JNDI
|
||||
resources under the key "UserDatabase". Any edits
|
||||
that are performed against this UserDatabase are immediately
|
||||
available for use by the Realm. -->
|
||||
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
|
||||
resourceName="UserDatabase"/>
|
||||
|
||||
<!-- Define the default virtual host
|
||||
Note: XML Schema validation will not work with Xerces 2.2.
|
||||
-->
|
||||
<Host name="localhost" appBase="webapps"
|
||||
unpackWARs="true" autoDeploy="true"
|
||||
xmlValidation="false" xmlNamespaceAware="false">
|
||||
|
||||
<!-- SingleSignOn valve, share authentication between web applications
|
||||
Documentation at: /docs/config/valve.html -->
|
||||
<!--
|
||||
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
|
||||
-->
|
||||
|
||||
<!-- Access log processes all example.
|
||||
Documentation at: /docs/config/valve.html -->
|
||||
<Valve className="org.apache.catalina.valves.FastCommonAccessLogValve" directory="logs"
|
||||
prefix="access_log." suffix=".txt" pattern="common" resolveHosts="false"/>
|
||||
|
||||
</Host>
|
||||
</Engine>
|
||||
</Service>
|
||||
</Server>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<tomcat-users>
|
||||
<!--
|
||||
<role rolename="tomcat"/>
|
||||
<role rolename="role1"/>
|
||||
<user username="tomcat" password="tomcat" roles="tomcat"/>
|
||||
<user username="both" password="tomcat" roles="tomcat,role1"/>
|
||||
<user username="role1" password="tomcat" roles="role1"/>
|
||||
-->
|
||||
|
||||
<!-- The host manager webapp is restricted to users with role "admin" -->
|
||||
<!--<user name="tomcat" password="password" roles="admin" />-->
|
||||
<!-- The manager webapp is restricted to users with role "manager" -->
|
||||
<!--<user name="tomcat" password="password" roles="manager" />-->
|
||||
</tomcat-users>
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# System-wide configuration file for tomcat6 services
|
||||
# This will be sourced by tomcat6 and any secondary service
|
||||
# Values will be overridden by service-specific configuration
|
||||
# files in /etc/sysconfig
|
||||
#
|
||||
# Use this one to change default values for all services
|
||||
# Change the service specific ones to affect only one service
|
||||
# (see, for instance, /etc/sysconfig/tomcat6)
|
||||
#
|
||||
|
||||
# Where your java installation lives
|
||||
#JAVA_HOME="/usr/lib/jvm/java"
|
||||
|
||||
# Where your tomcat installation lives
|
||||
CATALINA_BASE="/usr/share/cloud/bridge"
|
||||
CATALINA_HOME="/usr/share/tomcat6"
|
||||
JASPER_HOME="/usr/share/cloud/bridge"
|
||||
CATALINA_TMPDIR="/usr/share/cloud/bridge/temp"
|
||||
|
||||
# You can pass some parameters to java here if you wish to
|
||||
#JAVA_OPTS="-Xminf0.1 -Xmaxf0.3"
|
||||
|
||||
# Use JAVA_OPTS to set java.library.path for libtcnative.so
|
||||
#JAVA_OPTS="-Djava.library.path=/usr/lib64"
|
||||
JAVA_OPTS="-Djava.awt.headless=true -Xmx128M -XX:+HeapDumpOnOutOfMemoryError"
|
||||
|
||||
# What user should run tomcat
|
||||
TOMCAT_USER="cloud"
|
||||
# Do not remove the following line
|
||||
TOMCAT6_USER="$TOMCAT_USER"
|
||||
|
||||
TOMCAT_LOG="$CATALINA_BASE/logs/catalina.out"
|
||||
|
||||
# You can change your tomcat locale here
|
||||
#LANG="en_US"
|
||||
|
||||
# Run tomcat under the Java Security Manager
|
||||
SECURITY_MANAGER="false"
|
||||
|
||||
# Time to wait in seconds, before killing process
|
||||
SHUTDOWN_WAIT="30"
|
||||
|
||||
# Whether to annoy the user with "attempting to shut down" messages or not
|
||||
SHUTDOWN_VERBOSE="false"
|
||||
|
||||
# Set the TOMCAT_PID location
|
||||
CATALINA_PID="/var/run/cloud-bridge.pid"
|
||||
|
||||
# Connector port is 8080 for this tomcat6 instance
|
||||
CONNECTOR_PORT="8090"
|
||||
|
||||
# We pick up the classpath in the next line
|
||||
|
||||
dummy=1 ; . $CATALINA_BASE/conf/classpath.conf
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,17 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>awsapi</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>awsapi</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.python.pydev.PyDevBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.python.pydev.pythonNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<?eclipse-pydev version="1.0"?>
|
||||
|
||||
<pydev_project>
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
|
||||
</pydev_project>
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
=========================================================================
|
||||
== NOTICE file corresponding to the section 4 d of ==
|
||||
== the Apache License, Version 2.0, ==
|
||||
== in this case for the Apache Axis2 distribution. ==
|
||||
=========================================================================
|
||||
|
||||
This product includes software developed by
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
Portions Copyright 2006 International Business Machines Corp.
|
||||
Portions Copyright 2005-2007 WSO2, Inc.
|
||||
|
||||
This product also includes schemas and specification developed by:
|
||||
- the W3C consortium (http://www.w3c.org)
|
||||
|
||||
This product also includes WS-* schemas developed by International
|
||||
Business Machines Corporation, Microsoft Corporation, BEA Systems,
|
||||
TIBCO Software, SAP AG, Sonic Software, and VeriSign
|
||||
|
||||
This product also includes a WSDL developed by salesforce.com
|
||||
- Copyright 1999-2006 salesforce.com, inc.
|
||||
|
||||
Portions of the included xmlbeans library were originally based on the following:
|
||||
- software copyright (c) 2000-2003, BEA Systems, <http://www.bea.com/>.
|
||||
|
||||
Please read the different LICENSE files present in the lib directory of
|
||||
this distribution.
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
======================================================
|
||||
Apache Axis2 1.6.2 build (17-04-2012)
|
||||
|
||||
http://axis.apache.org/axis2/java/core/
|
||||
------------------------------------------------------
|
||||
|
||||
___________________
|
||||
Building
|
||||
===================
|
||||
|
||||
We use Maven 2 (http://maven.apache.org) to build, and you'll find a
|
||||
pom.xml in each module, as well as at the top level. Use "mvn install"
|
||||
(or "mvn clean install" to clean up first) to build.
|
||||
|
||||
IMPORTANT: the *first* time you build a given version of Axis2, you will not
|
||||
be able to do a regular "mvn install" from the top level - this is because
|
||||
we have a couple of custom Maven plugins that (due to some dependency-
|
||||
resolution issues in Maven) must be built and installed in your local
|
||||
repository before a build will succeed. This means you need to do one
|
||||
of the following:
|
||||
|
||||
1) Use ant (http://ant.apache.org) to build the first time. There is
|
||||
a build.xml at the top level which automatically builds the plugins
|
||||
first and then runs a regular "mvn install".
|
||||
|
||||
2) Manually "mvn install" both of the plugins in the following places:
|
||||
|
||||
modules/tool/axis2-mar-maven-plugin
|
||||
modules/tool/axis2-aar-maven-plugin
|
||||
|
||||
___________________
|
||||
Documentation
|
||||
===================
|
||||
|
||||
Documentation can be found in the 'docs' distribution of this release
|
||||
and in the main site.
|
||||
|
||||
___________________
|
||||
Deploying
|
||||
===================
|
||||
|
||||
To deploy a new Web service in Axis2 the following three steps must
|
||||
be performed:
|
||||
1) Create the Web service implementation class, supporting classes
|
||||
and the services.xml file,
|
||||
2) Archive the class files into a jar with the services.xml file in
|
||||
the META-INF directory
|
||||
3) Drop the jar file to the $AXIS2_HOME/WEB-INF/services directory
|
||||
where $AXIS2_HOME represents the install directory of your Axis2
|
||||
runtime. (In the case of a servelet container this would be the
|
||||
"axis2" directory inside "webapps".)
|
||||
|
||||
To verify the deployment please go to http://<yourip>:<port>/axis2/ and
|
||||
follow the "Services" Link.
|
||||
|
||||
For more information please refer to the User's Guide.
|
||||
|
||||
___________________
|
||||
Support
|
||||
===================
|
||||
|
||||
Any problem with this release can be reported to Axis mailing list
|
||||
or in the JIRA issue tracker. If you are sending an email to the mailing
|
||||
list make sure to add the [Axis2] prefix to the subject.
|
||||
|
||||
Mailing list subscription:
|
||||
java-dev-subscribe@axis.apache.org
|
||||
|
||||
Jira:
|
||||
http://issues.apache.org/jira/browse/AXIS2
|
||||
|
||||
|
||||
Thank you for using Axis2!
|
||||
|
||||
The Axis2 Team.
|
||||
Binary file not shown.
|
|
@ -1,7 +1,15 @@
|
|||
host=http://localhost:8080/bridge
|
||||
<<<<<<< HEAD
|
||||
storage.root=c:\\temp\\s3repo
|
||||
storage.multipartDir=__multipart__uploads__
|
||||
bucket.dns=true
|
||||
serviceEndpoint=s3.amazonaws.com
|
||||
=======
|
||||
storage.root=/Users/john1/S3-Mount
|
||||
storage.multipartDir=__multipart__uploads__
|
||||
bucket.dns=false
|
||||
serviceEndpoint=localhost:8080
|
||||
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,5 +4,12 @@ cloudstackVersion=2.2.0
|
|||
WSDLVersion=2010-11-15
|
||||
keystore=xes.keystore
|
||||
keystorePass=apache
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
dbHost=localhost
|
||||
dbName=cloudbridge
|
||||
dbUser=cloud
|
||||
dbPassword=cloud
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,12 @@
|
|||
<hibernate-configuration>
|
||||
<session-factory>
|
||||
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
<property name="hibernate.connection.url">jdbc:mysql://localhost/cloudbridge</property>
|
||||
<property name="hibernate.connection.username">cloud</property>
|
||||
<property name="hibernate.connection.password">cloud</property>
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
<property name="hibernate.connection.pool_size">20</property>
|
||||
<property name="hibernate.connection.autocommit">false</property>
|
||||
|
||||
|
|
@ -16,10 +22,17 @@
|
|||
|
||||
<property name="show_sql">true</property>
|
||||
<!-- to debug hibernate generated SQL, open following configuration property -->
|
||||
<<<<<<< HEAD
|
||||
<!--
|
||||
<property name="show_sql">true</property>
|
||||
<property name="hibernate.format_sql">true</property>
|
||||
-->
|
||||
=======
|
||||
<!--
|
||||
<property name="show_sql">true</property>
|
||||
<property name="hibernate.format_sql">true</property>
|
||||
-->
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
<!-- Mapping files -->
|
||||
<mapping resource="com/cloud/bridge/model/UserCredentials.hbm.xml"/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
|
||||
|
||||
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
|
||||
|
||||
<!-- ================================= -->
|
||||
<!-- Preserve messages in a local file -->
|
||||
<!-- ================================= -->
|
||||
|
||||
<!-- A time/date based rolling appender -->
|
||||
<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
|
||||
<param name="File" value="${catalina.base}/logs/cloudbridge.log"/>
|
||||
<param name="Append" value="true"/>
|
||||
<param name="Threshold" value="DEBUG"/>
|
||||
|
||||
<!-- Rollover at midnight each day -->
|
||||
<param name="DatePattern" value="'.'yyyy-MM-dd"/>
|
||||
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
<param name="ConversionPattern" value="%d %-5p [%c{3}] (%t:%x) %m%n"/>
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<!-- ============================== -->
|
||||
<!-- Append messages to the console -->
|
||||
<!-- ============================== -->
|
||||
|
||||
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
|
||||
<param name="Target" value="System.out"/>
|
||||
<param name="Threshold" value="DEBUG"/>
|
||||
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
<param name="ConversionPattern" value="%d{ABSOLUTE} %5p %c{1}:%L - %m%n"/>
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<!-- ================ -->
|
||||
<!-- Limit categories -->
|
||||
<!-- ================ -->
|
||||
|
||||
<category name="com.cloud">
|
||||
<priority value="DEBUG"/>
|
||||
</category>
|
||||
|
||||
<!-- Limit the org.apache category to INFO as its DEBUG is verbose -->
|
||||
<category name="org.apache">
|
||||
<priority value="INFO"/>
|
||||
</category>
|
||||
|
||||
<category name="org">
|
||||
<priority value="INFO"/>
|
||||
</category>
|
||||
|
||||
<category name="net">
|
||||
<priority value="INFO"/>
|
||||
</category>
|
||||
|
||||
<!-- ======================= -->
|
||||
<!-- Setup the Root category -->
|
||||
<!-- ======================= -->
|
||||
|
||||
<root>
|
||||
<level value="INFO"/>
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="FILE"/>
|
||||
</root>
|
||||
|
||||
</log4j:configuration>
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
To generate the Java AXIS2 classes from the Amazon EC2 wsdl use the following command line, assuming source definitions in the local directory:
|
||||
$ wsdl2java.sh -ss -sd -ssi -g -p com.amazon.s3 -ns2p "http://s3.amazonaws.com/doc/2006-03-01/"=com.amazon.s3 -uri cloud-AmazonS3.wsdl
|
||||
|
||||
This runs the wsdl2java code generation tool to produce stubs with asynchronous invocation methods, such as those useful for REST using the com.amazon.s3 package.
|
||||
|
||||
This creates the following java source files in the src/com/amazon/s3 subdirectory …
|
||||
|
||||
AccessControlList.java ListAllMyBucketsResponse.java
|
||||
AccessControlPolicy.java ListAllMyBucketsResult.java
|
||||
AmazonCustomerByEmail.java ListBucket.java
|
||||
AmazonS3CallbackHandler.java ListBucketResponse.java
|
||||
AmazonS3MessageReceiverInOut.java ListBucketResult.java
|
||||
AmazonS3Skeleton.java ListEntry.java
|
||||
AmazonS3SkeletonInterface.java ListVersionsResponse.java
|
||||
AmazonS3Stub.java ListVersionsResult.java
|
||||
BucketLoggingStatus.java ListVersionsResultChoice_type0.java
|
||||
CanonicalUser.java LocationConstraint.java
|
||||
CopyObject.java LoggingSettings.java
|
||||
CopyObjectResponse.java MetadataDirective.java
|
||||
CopyObjectResult.java MetadataEntry.java
|
||||
CreateBucket.java MfaDeleteStatus.java
|
||||
CreateBucketConfiguration.java NotificationConfiguration.java
|
||||
CreateBucketResponse.java Payer.java
|
||||
CreateBucketResult.java Permission.java
|
||||
DeleteBucket.java PostResponse.java
|
||||
DeleteBucketResponse.java PrefixEntry.java
|
||||
DeleteMarkerEntry.java PutObject.java
|
||||
DeleteObject.java PutObjectInline.java
|
||||
DeleteObjectResponse.java PutObjectInlineResponse.java
|
||||
ExtensionMapper.java PutObjectResponse.java
|
||||
GetBucketAccessControlPolicy.java PutObjectResult.java
|
||||
GetBucketAccessControlPolicyResponse.java RequestPaymentConfiguration.java
|
||||
GetBucketLoggingStatus.java Result.java
|
||||
GetBucketLoggingStatusResponse.java SetBucketAccessControlPolicy.java
|
||||
GetObject.java SetBucketAccessControlPolicyResponse.java
|
||||
GetObjectAccessControlPolicy.java SetBucketLoggingStatus.java
|
||||
GetObjectAccessControlPolicyResponse.java SetBucketLoggingStatusResponse.java
|
||||
GetObjectExtended.java SetObjectAccessControlPolicy.java
|
||||
GetObjectExtendedResponse.java SetObjectAccessControlPolicyResponse.java
|
||||
GetObjectResponse.java Status.java
|
||||
GetObjectResult.java StorageClass.java
|
||||
Grant.java TopicConfiguration.java
|
||||
Grantee.java User.java
|
||||
Group.java VersionEntry.java
|
||||
ListAllMyBuckets.java VersioningConfiguration.java
|
||||
ListAllMyBucketsEntry.java VersioningStatus.java
|
||||
ListAllMyBucketsList.java
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,123 @@
|
|||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="">
|
||||
<title>Welcome to Apache Axis2 version 1.6.2</title>
|
||||
</head>
|
||||
|
||||
<body lang="en">
|
||||
<h1>Welcome to Apache Axis2 version 1.6.2</h1>
|
||||
|
||||
<h3>April 17, 2012</h3>
|
||||
|
||||
<pre>Axis2 1.6.2 is a maintenance release that upgrades Axiom to version 1.2.13 and
|
||||
Neethi to version 3.0.2. it contains fixes for several issues discovered
|
||||
over the last six months. The complete list can be found <a href="http://s.apache.org/7lT">here</a>.
|
||||
|
||||
|
||||
About Axis2
|
||||
|
||||
Downloads are available at:
|
||||
http://axis.apache.org/axis2/java/core/download.cgi
|
||||
|
||||
Apache Axis2 is a complete re-design and re-write of the widely used
|
||||
Apache Axis engine and is a more efficient, more scalable, more modular
|
||||
and more XML-oriented Web services framework. It is carefully designed to
|
||||
support the easy addition of plug-in "modules" that extend its
|
||||
functionality for features such as security and reliability.
|
||||
|
||||
Modules supporting WS-Security/Secure-Conversation (Apache Rampart),
|
||||
WS-Trust (Apache Rahas), WS-Reliable Messaging (Apache Sandesha) and
|
||||
WS-Eventing (Apache Savan) will be available soon after the Apache Axis2
|
||||
@axisVersion@ release. Please see these projects' own sites for further information.
|
||||
|
||||
Known Issues and Limitations in 1.6.2 Release:
|
||||
- Please see JIRA
|
||||
|
||||
We are striving for a simple and happy first time user experience as well as a
|
||||
satisfying experienced user experience with this release. We welcome any
|
||||
and all feedback at:
|
||||
java-user@axis.apache.org (please include "[axis2]" in the subject)
|
||||
java-dev@axis.apache.org (please include "[axis2]" in the subject)
|
||||
http://issues.apache.org/jira/browse/AXIS2
|
||||
|
||||
Thank you for your interest in Apache Axis2!
|
||||
|
||||
The Axis2 Development Team
|
||||
http://axis.apache.org/axis2/java/core/
|
||||
|
||||
------------------------------------------------------------------------------------
|
||||
|
||||
Features of Apache Axis2:
|
||||
|
||||
Programming Model
|
||||
- Simple XML-centric client API with full WSDL and policy support
|
||||
- Support for POJO and Spring services and clients
|
||||
- Support for any message exchange pattern (MEP)
|
||||
- Synchronous and asynchronous programming model
|
||||
- Archived service deployment model supporting full service
|
||||
encapsulation with versioning support
|
||||
- Archived module deployment model supporting controlled
|
||||
extensibility with versioning support
|
||||
- Hot deployment
|
||||
- WS-Policy driven code generation extensions
|
||||
- Flexible service life cycle model
|
||||
- Automatic support for POX (REST) style invocation of services
|
||||
- Support for querying service's WSDL (with ?wsdl), schema (with
|
||||
?xsd) and policies (with ?policy)
|
||||
|
||||
Supported Specifications
|
||||
- SOAP 1.1 and 1.2
|
||||
- Message Transmission Optimization Mechanism (MTOM)
|
||||
- XML Optimized Packaging (XOP)
|
||||
- SOAP with Attachments
|
||||
- WSDL 1.1, including both SOAP and HTTP bindings , WSDL 2.0
|
||||
- WS-Addressing submission and 1.0
|
||||
- WS-Policy
|
||||
- SAAJ 1.1
|
||||
|
||||
Transports
|
||||
- HTTP
|
||||
- SMTP
|
||||
- JMS
|
||||
- TCP
|
||||
- udp
|
||||
- xmpp
|
||||
|
||||
For more details refer to the <a href="http://axis.apache.org/axis2/java/transports/">Axis2 Transports</a> project.
|
||||
|
||||
Supported Data Bindings
|
||||
- Axis Data Binding (ADB)
|
||||
- XMLBeans
|
||||
- JibX
|
||||
- JAXB
|
||||
|
||||
Tools
|
||||
- WSDL2Java: Generate Java stubs and skeletons from a WSDL document.
|
||||
- Java2WSDL: Generate a WSDL document from a Java class.
|
||||
- Eclipse Plugins
|
||||
- IntelliJ Idea Plugins
|
||||
- Maven2 Plugins
|
||||
- Web application for administering Apache Axis2
|
||||
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
1.0.2.RC6
|
||||
=========
|
||||
|
||||
|
|
@ -10,6 +11,8 @@
|
|||
|
||||
* Fixed ec2-register/registerTemplate calls
|
||||
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
1.0.2.RC4
|
||||
=========
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,12 @@ import com.cloud.bridge.persist.dao.UserCredentialsDao;
|
|||
import com.cloud.bridge.service.UserContext;
|
||||
import com.cloud.bridge.util.S3SoapAuth;
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
/*
|
||||
* For SOAP compatibility.
|
||||
*/
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
public class AuthenticationHandler implements Handler {
|
||||
protected final static Logger logger = Logger.getLogger(AuthenticationHandler.class);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,617 @@
|
|||
/* Took the basic code from Axis 1.2 and modified to fit into the cloud code base */
|
||||
|
||||
/*
|
||||
* Copyright 2001-2004 The Apache Software Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.cloud.bridge.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* This class takes the input stream and turns it multiple streams.
|
||||
DIME version 0 format
|
||||
<pre>
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---
|
||||
| VERSION |B|E|C| TYPE_T| OPT_T | OPTIONS_LENGTH | A
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| ID_LENGTH | TYPE_LENGTH | Always present 12 bytes
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ even on chunked data.
|
||||
| DATA_LENGTH | V
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---
|
||||
| /
|
||||
/ OPTIONS + PADDING /
|
||||
/ (absent for version 0) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| /
|
||||
/ ID + PADDING /
|
||||
/ |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| /
|
||||
/ TYPE + PADDING /
|
||||
/ |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| /
|
||||
/ DATA + PADDING /
|
||||
/ |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
</pre>
|
||||
* This implementation of input stream does not support marking operations.
|
||||
*
|
||||
* Incoming data is DIME encoded when its MIME type is "application/dime".
|
||||
* Then use this class to pull out 2 streams:
|
||||
* (1) The first stream is the SOAP request,
|
||||
* (2) The second stream is a chunked attachment (e.g., a file to store)
|
||||
*
|
||||
* The DIME format is defined at this reference:
|
||||
* http://msdn.microsoft.com/en-us/library/aa480488.aspx
|
||||
*
|
||||
* @author Rick Rineholt
|
||||
*/
|
||||
public class DimeDelimitedInputStream extends FilterInputStream
|
||||
{
|
||||
protected final static Logger logger = Logger.getLogger(DimeDelimitedInputStream.class);
|
||||
|
||||
InputStream is = null; //The source input stream.
|
||||
boolean closed = true; //The stream has been closed.
|
||||
boolean theEnd = false; //There are no more streams left.
|
||||
boolean moreChunks = false; //More chunks are a coming!
|
||||
boolean MB = false; //Message begin flag
|
||||
boolean ME = false; //Message end flag
|
||||
String type = null; //
|
||||
String id = null; //
|
||||
String tnf = null; //DIME type format
|
||||
long recordLength = 0L; //length of the current record.
|
||||
long bytesRead = 0L; //How many bytes of the current record have been read.
|
||||
int dataPadLength = 0; //How many pad bytes there are.
|
||||
|
||||
protected int streamNo = 0;
|
||||
protected IOException streamInError = null;
|
||||
|
||||
private static byte[] trash = new byte[4];
|
||||
protected static int streamCount = 0; //number of streams produced.
|
||||
|
||||
protected static synchronized int newStreamNo()
|
||||
{
|
||||
logger.debug( "streamNo " + (streamCount + 1));
|
||||
return ++streamCount;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* There can be multiple streams in a DIME encoding. For example, the first
|
||||
* stream can be a SOAP message, and the second stream a binary attachment (e.g.,
|
||||
* a file). During reading after an EOF is returned, this function should be
|
||||
* called to see if there is another stream following the last.
|
||||
*
|
||||
* @return the dime delimited stream, null if there are no more streams
|
||||
* @throws IOException if there was an error loading the data for the next stream
|
||||
*/
|
||||
public synchronized DimeDelimitedInputStream getNextStream() throws IOException
|
||||
{
|
||||
if (null != streamInError) throw streamInError;
|
||||
if (theEnd) return null;
|
||||
|
||||
//Each Stream must be read in succession
|
||||
if (bytesRead < recordLength || moreChunks)
|
||||
throw new RuntimeException("attach.dimeReadFullyError");
|
||||
|
||||
dataPadLength -= readPad(dataPadLength);
|
||||
|
||||
//Create an new dime stream that comes after this one.
|
||||
return new DimeDelimitedInputStream( this.is );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new dime stream.
|
||||
*
|
||||
* @param is the <code>InputStream</code> to wrap
|
||||
* @throws IOException if anything goes wrong
|
||||
*/
|
||||
public DimeDelimitedInputStream( InputStream is ) throws IOException
|
||||
{
|
||||
super(null);
|
||||
streamNo = newStreamNo();
|
||||
closed = false;
|
||||
this.is = is;
|
||||
readHeader( false );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make sure to skip the pad which appear in several parts of a DIME message.
|
||||
* @param size
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private final int readPad( int size ) throws IOException
|
||||
{
|
||||
if (0 == size) return 0;
|
||||
int read = readFromStream(trash, 0, size);
|
||||
|
||||
if (size != read)
|
||||
{
|
||||
streamInError = new IOException("attach.dimeNotPaddedCorrectly");
|
||||
throw streamInError;
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
|
||||
private final int readFromStream( byte[] b ) throws IOException
|
||||
{
|
||||
return readFromStream( b, 0, b.length );
|
||||
}
|
||||
|
||||
private final int readFromStream( byte[] b, int start, int length ) throws IOException
|
||||
{
|
||||
int br = 0;
|
||||
int brTotal = 0;
|
||||
|
||||
if (length == 0) return 0;
|
||||
|
||||
do
|
||||
{ try
|
||||
{
|
||||
br = is.read( b, brTotal + start, length - brTotal );
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
streamInError = e;
|
||||
throw e;
|
||||
}
|
||||
if (br > 0) brTotal += br;
|
||||
}
|
||||
while( br > -1 && brTotal < length );
|
||||
|
||||
return br > -1 ? brTotal : br;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the id for this stream part.
|
||||
* @return the id;
|
||||
*/
|
||||
public String getContentId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getDimeTypeNameFormat()
|
||||
{
|
||||
return tnf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type, as read from the header.
|
||||
* @return the type of this dime
|
||||
*/
|
||||
public String getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read from the DIME stream.
|
||||
*
|
||||
* @param b is the array to read into.
|
||||
* @param off is the offset
|
||||
* @return the number of bytes read. -1 if endof stream
|
||||
* @throws IOException if data could not be read from the stream
|
||||
*/
|
||||
public synchronized int read( byte[] b, int off, int len ) throws IOException
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
dataPadLength -= readPad(dataPadLength);
|
||||
throw new IOException( "streamClosed" );
|
||||
}
|
||||
return _read( b, off, len );
|
||||
}
|
||||
|
||||
|
||||
protected int _read( byte[] b, int off, int len ) throws IOException
|
||||
{
|
||||
int totalbytesread = 0;
|
||||
int bytes2read = 0;
|
||||
|
||||
if (len < 0)
|
||||
throw new IllegalArgumentException( "attach.readLengthError" + len );
|
||||
|
||||
if (off < 0)
|
||||
throw new IllegalArgumentException( "attach.readOffsetError" + off );
|
||||
|
||||
if (b == null)
|
||||
throw new IllegalArgumentException( "attach.readArrayNullError" );
|
||||
|
||||
if (b.length < off + len)
|
||||
throw new IllegalArgumentException("attach.readArraySizeError " + b.length + " " + len + " " + off );
|
||||
|
||||
if (null != streamInError) throw streamInError;
|
||||
if (0 == len) return 0; //quick.
|
||||
|
||||
// odd case no data to read -- give back 0 next time -1;
|
||||
if (recordLength == 0 && bytesRead == 0 && !moreChunks)
|
||||
{
|
||||
++bytesRead;
|
||||
if (ME) finalClose();
|
||||
return 0;
|
||||
}
|
||||
if (bytesRead >= recordLength && !moreChunks)
|
||||
{
|
||||
dataPadLength -= readPad( dataPadLength );
|
||||
if (ME) finalClose();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
do
|
||||
{ if (bytesRead >= recordLength && moreChunks) readHeader( true );
|
||||
bytes2read = (int) Math.min( recordLength - bytesRead, (long)len - totalbytesread );
|
||||
|
||||
try
|
||||
{ bytes2read = is.read( b, off + totalbytesread, bytes2read );
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
streamInError = e;
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (0 < bytes2read)
|
||||
{
|
||||
totalbytesread += bytes2read;
|
||||
bytesRead += bytes2read;
|
||||
}
|
||||
}
|
||||
while( bytes2read > -1 && totalbytesread < len && (bytesRead < recordLength || moreChunks));
|
||||
|
||||
if ( 0 > bytes2read )
|
||||
{
|
||||
if (moreChunks)
|
||||
{
|
||||
streamInError = new IOException("attach.DimeStreamError0");
|
||||
throw streamInError;
|
||||
}
|
||||
if (bytesRead < recordLength)
|
||||
{
|
||||
streamInError = new IOException("attach.DimeStreamError1 " + (recordLength - bytesRead));
|
||||
throw streamInError;
|
||||
}
|
||||
if (!ME)
|
||||
{
|
||||
streamInError = new IOException("attach.DimeStreamError0");
|
||||
throw streamInError;
|
||||
}
|
||||
//in theory the last chunk of data should also have been padded, but lets be tolerant of that.
|
||||
dataPadLength = 0;
|
||||
}
|
||||
else if (bytesRead >= recordLength)
|
||||
{
|
||||
//get rid of pading.
|
||||
try
|
||||
{ dataPadLength -= readPad( dataPadLength );
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
//in theory the last chunk of data should also have been padded, but lets be tolerant of that.
|
||||
if (!ME) throw e;
|
||||
else
|
||||
{
|
||||
dataPadLength = 0;
|
||||
streamInError = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bytesRead >= recordLength && ME) finalClose();
|
||||
|
||||
return totalbytesread >= 0 ? totalbytesread : -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The DIME header is read into local class data fields and are not
|
||||
* passed as part of the stream data.
|
||||
*
|
||||
* @param isChunk
|
||||
* @throws IOException
|
||||
*/
|
||||
protected void readHeader( boolean isChunk ) throws IOException
|
||||
{
|
||||
bytesRead = 0; //How many bytes of the record have been read.
|
||||
|
||||
if (isChunk)
|
||||
{
|
||||
if (!moreChunks) throw new RuntimeException("attach.DimeStreamError2");
|
||||
dataPadLength -= readPad(dataPadLength); //Just in case it was left over.
|
||||
}
|
||||
|
||||
byte[] header = new byte[12];
|
||||
|
||||
if (header.length != readFromStream( header) )
|
||||
{
|
||||
streamInError = new IOException("attach.DimeStreamError3 " + header.length );
|
||||
throw streamInError;
|
||||
}
|
||||
|
||||
//VERSION
|
||||
byte version = (byte) ((header[0] >>> 3) & 0x1f);
|
||||
if (version > 1)
|
||||
{
|
||||
streamInError = new IOException("attach.DimeStreamError4 " + version );
|
||||
throw streamInError;
|
||||
}
|
||||
|
||||
//B, E, C
|
||||
MB = 0 != (0x4 & header[0]);
|
||||
ME = 0 != (0x2 & header[0]);
|
||||
moreChunks = 0 != (0x1 & header[0]);
|
||||
|
||||
//TYPE_T
|
||||
if (!isChunk)
|
||||
{
|
||||
switch( ((header[1] >>> 4) & (byte)0x0f) ) {
|
||||
case 0x00: tnf = "UNCHANGED"; break;
|
||||
case 0x01: tnf = "MIME"; break;
|
||||
case 0x02: tnf = "URI"; break;
|
||||
default: tnf = "UNKNOWN"; break;
|
||||
}
|
||||
}
|
||||
|
||||
//OPTIONS_LENGTH
|
||||
int optionsLength = ((((int) header[2]) << 8) & 0xff00) | ((int) header[3]);
|
||||
|
||||
//ID_LENGTH
|
||||
int idLength = ((((int) header[4]) << 8) & 0xff00) | ((int) header[5]);
|
||||
|
||||
//TYPE_LENGTH
|
||||
int typeLength = ((((int) header[6]) << 8) & 0xff00) | ((int) header[7]);
|
||||
|
||||
//DATA_LENGTH
|
||||
recordLength = ((((long) header[8] ) << 24) & 0xff000000L) |
|
||||
((((long) header[9] ) << 16) & 0xff0000L ) |
|
||||
((((long) header[10]) << 8 ) & 0xff00L ) |
|
||||
((long) header[11] & 0xffL );
|
||||
|
||||
//OPTIONS + PADDING
|
||||
if (0 != optionsLength)
|
||||
{
|
||||
byte[] optBytes = new byte[optionsLength];
|
||||
|
||||
if (optionsLength != readFromStream( optBytes ))
|
||||
{
|
||||
streamInError = new IOException("attach.DimeStreamError5 " + optionsLength );
|
||||
throw streamInError;
|
||||
}
|
||||
optBytes = null; // throw it away, don't know anything about options.
|
||||
|
||||
int pad = (int) ((4L - (optionsLength & 0x3L)) & 0x03L);
|
||||
|
||||
if (pad != readFromStream( header, 0, pad ))
|
||||
{
|
||||
streamInError = new IOException("attach.DimeStreamError7");
|
||||
throw streamInError;
|
||||
}
|
||||
}
|
||||
|
||||
// ID + PADDING
|
||||
if (0 < idLength)
|
||||
{
|
||||
byte[] idBytes = new byte[ idLength];
|
||||
|
||||
if (idLength != readFromStream( idBytes ))
|
||||
{
|
||||
streamInError = new IOException("attach.DimeStreamError8");
|
||||
throw streamInError;
|
||||
}
|
||||
if (idLength != 0 && !isChunk) id = new String(idBytes);
|
||||
|
||||
int pad = (int) ((4L - (idLength & 0x3L)) & 0x03L);
|
||||
|
||||
if (pad != readFromStream( header, 0, pad ))
|
||||
{
|
||||
streamInError = new IOException("attach.DimeStreamError9");
|
||||
throw streamInError;
|
||||
}
|
||||
}
|
||||
|
||||
//TYPE + PADDING
|
||||
if (0 < typeLength)
|
||||
{
|
||||
byte[] typeBytes = new byte[typeLength];
|
||||
|
||||
if (typeLength != readFromStream( typeBytes ))
|
||||
{
|
||||
streamInError = new IOException("attach.DimeStreamError10");
|
||||
throw streamInError;
|
||||
}
|
||||
if (typeLength != 0 && !isChunk) type = new String(typeBytes);
|
||||
|
||||
int pad = (int) ((4L - (typeLength & 0x3L)) & 0x03L);
|
||||
|
||||
if (pad != readFromStream( header, 0, pad ))
|
||||
{
|
||||
streamInError = new IOException("attach.DimeStreamError11");
|
||||
throw streamInError;
|
||||
}
|
||||
}
|
||||
logger.debug("MB:" + MB + ", ME:" + ME + ", CF:" + moreChunks +
|
||||
"Option length:" + optionsLength +
|
||||
", ID length:" + idLength +
|
||||
", typeLength:" + typeLength + ", TYPE_T:" + tnf);
|
||||
logger.debug("id:\"" + id + "\"");
|
||||
logger.debug("type:\"" + type + "\"");
|
||||
logger.debug("recordlength:\"" + recordLength + "\"");
|
||||
|
||||
dataPadLength = (int) ((4L - (recordLength & 0x3L)) & 0x03L);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read from the delimited stream.
|
||||
*
|
||||
* @param b is the array to read into. Read as much as possible
|
||||
* into the size of this array.
|
||||
* @return the number of bytes read. -1 if endof stream
|
||||
* @throws IOException if data could not be read from the stream
|
||||
*/
|
||||
public int read( byte[] b ) throws IOException
|
||||
{
|
||||
return read( b, 0, b.length );
|
||||
}
|
||||
|
||||
|
||||
// fixme: this seems a bit inefficient
|
||||
/**
|
||||
* Read from the boundary delimited stream.
|
||||
*
|
||||
* @return the byte read, or -1 if endof stream
|
||||
* @throws IOException if there was an error reading the data
|
||||
*/
|
||||
public int read() throws IOException
|
||||
{
|
||||
byte[] b = new byte[1];
|
||||
int read = read( b, 0, 1 );
|
||||
|
||||
if (read < 0) return -1; // fixme: should we also check for read != 1?
|
||||
return (b[0] & 0xff); // convert byte value to a positive int
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closes the stream.
|
||||
* This will take care of flushing any remaining data to the stream.
|
||||
* Multiple calls to this method will result in the stream being closed once
|
||||
* and then all subsequent calls being ignored.
|
||||
*
|
||||
* @throws IOException if the stream could not be closed
|
||||
*/
|
||||
public void close() throws IOException
|
||||
{
|
||||
synchronized( this )
|
||||
{
|
||||
if (closed) return;
|
||||
closed = true; //mark it closed.
|
||||
}
|
||||
logger.debug("bStreamClosed " + streamNo);
|
||||
|
||||
if (bytesRead < recordLength || moreChunks)
|
||||
{
|
||||
//We need get this off the stream. Easy way to flush through the stream;
|
||||
byte[] readrest = new byte[1024 * 16];
|
||||
int bread = 0;
|
||||
|
||||
do
|
||||
{ bread = _read( readrest, 0, readrest.length ); //should also close the original stream.
|
||||
}
|
||||
while( bread > -1 );
|
||||
}
|
||||
dataPadLength -= readPad( dataPadLength );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Skip n bytes of data in the DIME stream, while reading and processing
|
||||
* any headers in the current stream.
|
||||
*
|
||||
* @param n - number of data bytes to skip
|
||||
* @return number of bytes actually skipped
|
||||
* @throws IOException
|
||||
*/
|
||||
public long skip( long n ) throws IOException
|
||||
{
|
||||
long bytesSkipped = 0;
|
||||
long bytes2Read = 0;
|
||||
byte[] dumpbytes = new byte[1024];
|
||||
|
||||
while( n > 0 )
|
||||
{
|
||||
bytes2Read = (n > 1024 ? 1024 : n);
|
||||
bytes2Read = _read( dumpbytes, 0, (int)bytes2Read );
|
||||
|
||||
n -= bytes2Read;
|
||||
bytesSkipped += bytes2Read;
|
||||
}
|
||||
|
||||
return bytesSkipped;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mark the stream. This is not supported.
|
||||
*/
|
||||
public void mark( int readlimit )
|
||||
{ //do nothing
|
||||
}
|
||||
|
||||
public void reset() throws IOException
|
||||
{
|
||||
streamInError = new IOException("attach.bounday.mns");
|
||||
throw streamInError;
|
||||
}
|
||||
|
||||
public boolean markSupported()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public synchronized int available() throws IOException
|
||||
{
|
||||
if (null != streamInError) throw streamInError;
|
||||
|
||||
int chunkAvail = (int) Math.min((long)Integer.MAX_VALUE, recordLength - bytesRead);
|
||||
int streamAvail = 0;
|
||||
|
||||
try
|
||||
{ streamAvail = is.available();
|
||||
}
|
||||
catch( IOException e )
|
||||
{
|
||||
streamInError = e;
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (chunkAvail == 0 && moreChunks && (12 + dataPadLength) <= streamAvail)
|
||||
{
|
||||
dataPadLength -= readPad(dataPadLength);
|
||||
readHeader( true );
|
||||
return available();
|
||||
}
|
||||
return Math.min( streamAvail, chunkAvail );
|
||||
}
|
||||
|
||||
|
||||
protected void finalClose() throws IOException
|
||||
{
|
||||
try
|
||||
{ theEnd = true;
|
||||
if(null != is) is.close();
|
||||
}
|
||||
finally
|
||||
{
|
||||
is= null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.cloud.bridge.io;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.activation.DataSource;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* @author Kelven Yang
|
||||
*/
|
||||
public class FileRangeDataSource implements DataSource {
|
||||
protected final static Logger logger = Logger.getLogger(FileRangeDataSource.class);
|
||||
|
||||
private FileRangeInputStream is;
|
||||
|
||||
public FileRangeDataSource(File file, long startPos, long endPos) throws IOException {
|
||||
is = new FileRangeInputStream(file, startPos, endPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
assert(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
assert(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
assert(false);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.cloud.bridge.io;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
/**
|
||||
* @author Kelven Yang
|
||||
*/
|
||||
public class FileRangeInputStream extends InputStream {
|
||||
private RandomAccessFile randomAccessFile;
|
||||
private long curPos;
|
||||
private long endPos;
|
||||
private long fileLength;
|
||||
|
||||
public FileRangeInputStream(File file, long startPos, long endPos) throws IOException {
|
||||
fileLength = file.length();
|
||||
|
||||
if(startPos > fileLength)
|
||||
startPos = fileLength;
|
||||
|
||||
if(endPos > fileLength)
|
||||
endPos = fileLength;
|
||||
|
||||
if(startPos > endPos)
|
||||
throw new IllegalArgumentException("Invalid file range " + startPos + "-" + endPos);
|
||||
|
||||
this.curPos = startPos;
|
||||
this.endPos = endPos;
|
||||
randomAccessFile = new RandomAccessFile(file, "r");
|
||||
randomAccessFile.seek(startPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return (int)(endPos - curPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if(available() > 0) {
|
||||
int value = randomAccessFile.read();
|
||||
curPos++;
|
||||
return value;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
int bytesToRead = Math.min(len, available());
|
||||
if(bytesToRead == 0)
|
||||
return -1;
|
||||
|
||||
int bytesRead = randomAccessFile.read(b, off, bytesToRead);
|
||||
if(bytesRead < 0)
|
||||
return -1;
|
||||
|
||||
curPos += bytesRead;
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
long skipped = Math.min(n, available());
|
||||
randomAccessFile.skipBytes((int)skipped);
|
||||
curPos += skipped;
|
||||
return skipped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
randomAccessFile.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package com.cloud.bridge.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import javax.xml.stream.XMLOutputFactory;
|
||||
|
||||
import org.apache.axiom.om.OMAbstractFactory;
|
||||
import org.apache.axiom.om.OMFactory;
|
||||
import org.apache.axis2.databinding.utils.writer.MTOMAwareXMLSerializer;
|
||||
import org.apache.axis2.databinding.ADBBean;
|
||||
import org.apache.axis2.databinding.ADBException;
|
||||
|
||||
/**
|
||||
* @author John Zucker
|
||||
* Provide an MTOM aware serializable output stream writer to be consumed by implementors of the
|
||||
* com.amazon.s3 Response ADB bean classes.
|
||||
* This writer enables participation is StaX based builders and AXIOM om xml stream processing
|
||||
* An instance of a MTOMAwareResultStreamWriter is a convenient argument to a com.amazon.s3 Response bean, as generated
|
||||
* from the Amazon S3 WSDL using
|
||||
* wsdl2java.sh -ss -sd -ssi -g -p com.amazon.s3 -ns2p "http://s3.amazonaws.com/doc/2006-03-01/"=com.amazon.s3 -uri cloud-AmazonS3.wsdl
|
||||
* Such a bean implements a serialize method of the form
|
||||
* public void serialize(qualifiedName,omfactory, xmlWriter)
|
||||
* where
|
||||
* @param qualifiedName is the XML qualified name of the parent
|
||||
* @param omfactory is an implementor of the AXIOM object model interface
|
||||
* @param xmlWriter is an implementor of XMLStxreamWriter for writing plain XML
|
||||
* A convenience constructor of MTOMAwareResultStreamWriter is of the form
|
||||
* MTOMAwareResultStreamWriter(nameOfResult, outputStream)
|
||||
* where
|
||||
* @param nameOfResult is the name used for the root (parent) tag by the serialization bean
|
||||
* @param outputStream is the (servlet) output stream into which the bytes are written
|
||||
* Addtionally, as a side effect, ensure that the org.apache.axis2.databinding classes which serialize the
|
||||
* output of each fields have been initialized to be aware of any custom classes which override the default
|
||||
* output xsd converter methods of Axis2's databinding. Such a custom class is notified to the ADB framework
|
||||
* (via its org.apache.axis2.databinding.utils.ConverterUtil class) by setting a System property,
|
||||
* SYSTEM_PROPERTY_ADB_CONVERTERUTIL to name the custom class.
|
||||
*/
|
||||
public class MTOMAwareResultStreamWriter {
|
||||
|
||||
// Standard XML prolog to add to the beginning of each XML document.
|
||||
public static final String
|
||||
XMLPROLOG = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
|
||||
private static final byte[] XMLPROLOGBYTES = XMLPROLOG.getBytes();
|
||||
|
||||
// The XML namespace used in documents transported to and from the service
|
||||
public static final String
|
||||
S3XMLNS = "http://s3.amazonaws.com/doc/2006-03-01/";
|
||||
// Prefix to use to represent the default XML Namespace, defined by the Namespaces in XML 3 spec to be ""
|
||||
public static final String
|
||||
DEFAULT_NS_PREFIX = XMLConstants.DEFAULT_NS_PREFIX;
|
||||
|
||||
private XMLStreamWriter xmlWriter = null;
|
||||
|
||||
private MTOMAwareXMLSerializer mtomWriter = null;
|
||||
|
||||
// A default instance of AXIOM object model factory suitable for constructing plain XML
|
||||
private OMFactory omfactory = OMAbstractFactory.getOMFactory();
|
||||
|
||||
// The qualified name for use in the XML schema as defined by http://www.w3.org/TR/xmlschema-2/#QName
|
||||
private QName qualifiedName = null;
|
||||
|
||||
// Usually bound to a servlet output stream
|
||||
private OutputStream outputStream = null;
|
||||
|
||||
|
||||
// Set the system property to notify the ADB framework of its custom class for system-wide side effect
|
||||
// at time of initialization of this class (executed once in any JVM running this application)
|
||||
static
|
||||
{
|
||||
System.setProperty
|
||||
(org.apache.axis2.databinding.utils.ConverterUtil.SYSTEM_PROPERTY_ADB_CONVERTERUTIL,
|
||||
"com.cloud.bridge.util.DatabindingConverterUtil");
|
||||
}
|
||||
|
||||
/*
|
||||
* @params
|
||||
* @param nameOfResult Used as the tag description of the result written out when the requester serializes
|
||||
* @param outputStream The stream capable of sinking bytes written at the time the requester is ready to serialize,
|
||||
* assumed to be a ServletOutputStream
|
||||
* @param xmlOutputFactory If passing a non-default factory, used to get an implementor of XmlStreamWriter
|
||||
* @throw XMLStreamException
|
||||
*/
|
||||
public MTOMAwareResultStreamWriter (String nameOfResult, OutputStream outputStream, XMLOutputFactory xmlOutputFactory)
|
||||
throws XMLStreamException
|
||||
{
|
||||
this.outputStream = outputStream;
|
||||
// Create an implementor of xmlWriter for this instance
|
||||
xmlWriter = xmlOutputFactory.createXMLStreamWriter(outputStream);
|
||||
// Create an MTOM aware XML serializer for this instance
|
||||
// An MTOMAwareXMLSerializer wraps a xmlStreamWriter and implements writeDataHandler
|
||||
mtomWriter = new MTOMAwareXMLSerializer( xmlWriter );
|
||||
// Create a new qualified name passing in namespace URI (default), localpart, prefix (default)
|
||||
qualifiedName = new QName (S3XMLNS, nameOfResult, DEFAULT_NS_PREFIX);
|
||||
}
|
||||
|
||||
/*
|
||||
* @params
|
||||
* @param nameOfResult Used as the tag description of the result written out when the requester serializes
|
||||
* @param outputStream The stream capable of sinking bytes written at the time the requester is ready to serialize,
|
||||
* assumed to be a ServletOutputStream
|
||||
* Uses default implementor of XmlStreamWriter
|
||||
* @throw XMLStreamException
|
||||
*/
|
||||
|
||||
public MTOMAwareResultStreamWriter (String nameOfResult, OutputStream outputStream)
|
||||
throws XMLStreamException
|
||||
{
|
||||
this (nameOfResult, outputStream, XMLOutputFactory.newInstance());
|
||||
}
|
||||
|
||||
// Housekeeping before consumption in a serialize call
|
||||
public void startWrite ()
|
||||
throws IOException
|
||||
{ outputStream.write(XMLPROLOGBYTES);
|
||||
|
||||
}
|
||||
|
||||
public void stopWrite ()
|
||||
throws IOException, XMLStreamException
|
||||
{
|
||||
xmlWriter.flush();
|
||||
xmlWriter.close();
|
||||
outputStream.close();
|
||||
}
|
||||
|
||||
// Cooperate with an instance of org.apache.axis2.databinding.ADBBean to provide serialization output of XML
|
||||
// An org.apache.axis2.databinding.ADBBean implements a serialize method which takes a QName and a XMLStreamWriter
|
||||
public void writeout
|
||||
(ADBBean dataBindingBean) throws ADBException, XMLStreamException
|
||||
{
|
||||
|
||||
dataBindingBean.serialize(qualifiedName, omfactory, mtomWriter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.cloud.bridge.io;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A DIME stream is actually composed of multiple encoded streams.
|
||||
* This class is a wrapper around the DimeDelimitedInputStream inorder
|
||||
* to provide a simple iterator like interface for all the streams in a
|
||||
* DIME encoded message.
|
||||
*/
|
||||
public class MultiPartDimeInputStream
|
||||
{
|
||||
protected final static Logger logger = Logger.getLogger(MultiPartDimeInputStream.class);
|
||||
|
||||
protected InputStream is = null;
|
||||
protected DimeDelimitedInputStream currentStream = null;
|
||||
|
||||
protected int count = 0;
|
||||
protected boolean eos = false;
|
||||
protected String contentId = null;
|
||||
protected String type = null;
|
||||
protected String typeFormat = null;
|
||||
|
||||
/**
|
||||
* The SOAP stream must be first, call nextInputStream to get
|
||||
* access to the first stream and all streams after that.
|
||||
*
|
||||
* @param is the true input stream holding the incoming request.
|
||||
*/
|
||||
public MultiPartDimeInputStream( InputStream is ) throws IOException
|
||||
{
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* These three methods are DIME specific but provide potentially
|
||||
* useful information about the current stream's data.
|
||||
*
|
||||
* @return URL or MIME type
|
||||
*/
|
||||
public String getStreamType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getStreamTypeFormat()
|
||||
{
|
||||
// Is the type a URI or MIME type or just unknown?
|
||||
return typeFormat;
|
||||
}
|
||||
|
||||
public String getStreamId()
|
||||
{
|
||||
// The soap body might have string identifiers to point to other streams in the message
|
||||
return contentId;
|
||||
}
|
||||
|
||||
public InputStream getInputStream()
|
||||
{
|
||||
return currentStream;
|
||||
}
|
||||
|
||||
public int available() throws IOException
|
||||
{
|
||||
if (eos) return -1;
|
||||
|
||||
if (null == currentStream)
|
||||
{
|
||||
throw new IOException( "streamClosed -- call nextInputStream()" );
|
||||
}
|
||||
return currentStream.available();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Move on to the next stream encoded in the DIME stream.
|
||||
* If the current stream has not been all read, then we skip the remaining bytes of
|
||||
* that stream.
|
||||
*
|
||||
* @return false if no next input stream, true if next input stream ready
|
||||
* @throws IOException
|
||||
*/
|
||||
public boolean nextInputStream() throws IOException
|
||||
{
|
||||
if ( null == currentStream )
|
||||
{
|
||||
// on the first call to this function get the first stream
|
||||
if (0 == count) currentStream = new DimeDelimitedInputStream( is );
|
||||
}
|
||||
else
|
||||
{ // make sure the bytes of the previous stream are all skipped before we start the next
|
||||
currentStream.close();
|
||||
contentId = null;
|
||||
type = null;
|
||||
typeFormat = null;
|
||||
currentStream = currentStream.getNextStream();
|
||||
}
|
||||
|
||||
if ( null != currentStream )
|
||||
{
|
||||
contentId = currentStream.getContentId();
|
||||
type = currentStream.getType();
|
||||
typeFormat = currentStream.getDimeTypeNameFormat();
|
||||
eos = false;
|
||||
count++;
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
|
||||
public long skip( long n ) throws IOException
|
||||
{
|
||||
if (eos || null == currentStream)
|
||||
{
|
||||
throw new IOException( "streamClosed -- call nextInputStream()" );
|
||||
}
|
||||
return currentStream.skip( n );
|
||||
}
|
||||
|
||||
|
||||
public int read( byte[] b, int off, int len ) throws IOException
|
||||
{
|
||||
if (eos || null == currentStream) return -1;
|
||||
|
||||
int read = currentStream.read( b, off, len );
|
||||
|
||||
if (read < 0) eos = true;
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
|
||||
public int read( byte[] b ) throws IOException
|
||||
{
|
||||
return read( b, 0, b.length );
|
||||
}
|
||||
|
||||
|
||||
public int read() throws IOException
|
||||
{
|
||||
if (eos || null == currentStream) return -1;
|
||||
|
||||
int ret = currentStream.read();
|
||||
|
||||
if (ret < 0) eos = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.cloud.bridge.io;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import javax.activation.DataHandler;
|
||||
import javax.activation.DataSource;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.bridge.service.core.s3.S3BucketAdapter;
|
||||
import com.cloud.bridge.service.core.s3.S3MultipartPart;
|
||||
import com.cloud.bridge.service.exception.FileNotExistException;
|
||||
import com.cloud.bridge.service.exception.InternalErrorException;
|
||||
import com.cloud.bridge.service.exception.OutOfStorageException;
|
||||
import com.cloud.bridge.util.StringHelper;
|
||||
import com.cloud.bridge.util.OrderedPair;
|
||||
|
||||
/**
|
||||
* @author Kelven Yang, John Zucker
|
||||
*/
|
||||
public class S3FileSystemBucketAdapter implements S3BucketAdapter {
|
||||
protected final static Logger logger = Logger.getLogger(S3FileSystemBucketAdapter.class);
|
||||
|
||||
public S3FileSystemBucketAdapter() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createContainer(String mountedRoot, String bucket) {
|
||||
|
||||
String dir = getBucketFolderDir(mountedRoot, bucket);
|
||||
File container = new File(dir);
|
||||
|
||||
if (!container.exists()) {
|
||||
if (!container.mkdirs())
|
||||
throw new OutOfStorageException("Unable to create " + dir + " for bucket " + bucket);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteContainer(String mountedRoot, String bucket) {
|
||||
String dir = getBucketFolderDir(mountedRoot, bucket);
|
||||
File path = new File(dir);
|
||||
if(!deleteDirectory(path))
|
||||
throw new OutOfStorageException("Unable to delete " + dir + " for bucket " + bucket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBucketFolderDir(String mountedRoot, String bucket) {
|
||||
String bucketFolder = getBucketFolderName(bucket);
|
||||
String dir;
|
||||
String separator = ""+File.separatorChar;
|
||||
if(!mountedRoot.endsWith(separator))
|
||||
dir = mountedRoot + separator + bucketFolder;
|
||||
else
|
||||
dir = mountedRoot + bucketFolder;
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String saveObject(InputStream is, String mountedRoot, String bucket, String fileName)
|
||||
{
|
||||
FileOutputStream fos = null;
|
||||
MessageDigest md5 = null;
|
||||
|
||||
try {
|
||||
md5 = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
logger.error("Unexpected exception " + e.getMessage(), e);
|
||||
throw new InternalErrorException("Unable to get MD5 MessageDigest", e);
|
||||
}
|
||||
|
||||
File file = new File(getBucketFolderDir(mountedRoot, bucket) + File.separatorChar + fileName);
|
||||
try {
|
||||
// -> when versioning is off we need to rewrite the file contents
|
||||
file.delete();
|
||||
file.createNewFile();
|
||||
|
||||
fos = new FileOutputStream(file);
|
||||
byte[] buffer = new byte[4096];
|
||||
int len = 0;
|
||||
while( (len = is.read(buffer)) > 0) {
|
||||
fos.write(buffer, 0, len);
|
||||
md5.update(buffer, 0, len);
|
||||
|
||||
}
|
||||
//Convert MD4 digest to (lowercase) hex String
|
||||
return StringHelper.toHexString(md5.digest());
|
||||
|
||||
}
|
||||
catch(IOException e) {
|
||||
logger.error("Unexpected exception " + e.getMessage(), e);
|
||||
throw new OutOfStorageException(e);
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (null != fos) fos.close();
|
||||
}
|
||||
catch( Exception e ) {
|
||||
logger.error("Can't close FileOutputStream " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* From a list of files (each being one part of the multipart upload), concatentate all files into a single
|
||||
* object that can be accessed by normal S3 calls. This function could take a long time since a multipart is
|
||||
* allowed to have upto 10,000 parts (each 5 gib long). Amazon defines that while this operation is in progress
|
||||
* whitespace is sent back to the client inorder to keep the HTTP connection alive.
|
||||
*
|
||||
* @param mountedRoot - where both the source and dest buckets are located
|
||||
* @param destBucket - resulting location of the concatenated objects
|
||||
* @param fileName - resulting file name of the concatenated objects
|
||||
* @param sourceBucket - special bucket used to save uploaded file parts
|
||||
* @param parts - an array of file names in the sourceBucket
|
||||
* @param client - if not null, then keep the servlet connection alive while this potentially long concatentation takes place
|
||||
* @return OrderedPair with the first value the MD5 of the final object, and the second value the length of the final object
|
||||
*/
|
||||
@Override
|
||||
public OrderedPair<String,Long> concatentateObjects(String mountedRoot, String destBucket, String fileName, String sourceBucket, S3MultipartPart[] parts, OutputStream client)
|
||||
{
|
||||
MessageDigest md5;
|
||||
long totalLength = 0;
|
||||
|
||||
try {
|
||||
md5 = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
logger.error("Unexpected exception " + e.getMessage(), e);
|
||||
throw new InternalErrorException("Unable to get MD5 MessageDigest", e);
|
||||
}
|
||||
|
||||
File file = new File(getBucketFolderDir(mountedRoot, destBucket) + File.separatorChar + fileName);
|
||||
try {
|
||||
// -> when versioning is off we need to rewrite the file contents
|
||||
file.delete();
|
||||
file.createNewFile();
|
||||
|
||||
final FileOutputStream fos = new FileOutputStream(file);
|
||||
byte[] buffer = new byte[4096];
|
||||
|
||||
// -> get the input stream for the next file part
|
||||
for( int i=0; i < parts.length; i++ )
|
||||
{
|
||||
DataHandler nextPart = loadObject( mountedRoot, sourceBucket, parts[i].getPath());
|
||||
InputStream is = nextPart.getInputStream();
|
||||
|
||||
int len = 0;
|
||||
while( (len = is.read(buffer)) > 0) {
|
||||
fos.write(buffer, 0, len);
|
||||
md5.update(buffer, 0, len);
|
||||
totalLength += len;
|
||||
}
|
||||
is.close();
|
||||
|
||||
// -> after each file write tell the client we are still here to keep connection alive
|
||||
if (null != client) {
|
||||
client.write( new String(" ").getBytes());
|
||||
client.flush();
|
||||
}
|
||||
}
|
||||
fos.close();
|
||||
return new OrderedPair<String, Long>(StringHelper.toHexString(md5.digest()), new Long(totalLength));
|
||||
//Create an ordered pair whose first element is the MD4 digest as a (lowercase) hex String
|
||||
}
|
||||
catch(IOException e) {
|
||||
logger.error("concatentateObjects unexpected exception " + e.getMessage(), e);
|
||||
throw new OutOfStorageException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataHandler loadObject(String mountedRoot, String bucket, String fileName) {
|
||||
File file = new File(getBucketFolderDir(mountedRoot, bucket) + File.separatorChar + fileName);
|
||||
try {
|
||||
return new DataHandler(file.toURL());
|
||||
} catch (MalformedURLException e) {
|
||||
throw new FileNotExistException("Unable to open underlying object file");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteObject(String mountedRoot, String bucket, String fileName) {
|
||||
String filePath = new String( getBucketFolderDir(mountedRoot, bucket) + File.separatorChar + fileName );
|
||||
File file = new File( filePath );
|
||||
if (!file.delete()) {
|
||||
logger.error("file: " + filePath + ", f=" + file.isFile() + ", h=" + file.isHidden() + ", e=" + file.exists() + ", w=" + file.canWrite());
|
||||
throw new OutOfStorageException( "Unable to delete " + filePath + " for object deletion" );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataHandler loadObjectRange(String mountedRoot, String bucket, String fileName, long startPos, long endPos) {
|
||||
File file = new File(getBucketFolderDir(mountedRoot, bucket) + File.separatorChar + fileName);
|
||||
try {
|
||||
DataSource ds = new FileRangeDataSource(file, startPos, endPos);
|
||||
return new DataHandler(ds);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new FileNotExistException("Unable to open underlying object file");
|
||||
} catch(IOException e) {
|
||||
throw new FileNotExistException("Unable to open underlying object file");
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean deleteDirectory(File path) {
|
||||
if( path.exists() ) {
|
||||
File[] files = path.listFiles();
|
||||
for(int i = 0; i < files.length; i++) {
|
||||
if(files[i].isDirectory()) {
|
||||
deleteDirectory(files[i]);
|
||||
} else {
|
||||
files[i].delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
return path.delete();
|
||||
}
|
||||
|
||||
private String getBucketFolderName(String bucket) {
|
||||
// temporary
|
||||
String name = bucket.replace(' ', '_');
|
||||
name = bucket.replace('\\', '-');
|
||||
name = bucket.replace('/', '-');
|
||||
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,11 @@ import org.apache.axis2.context.ConfigurationContext;
|
|||
import org.apache.axis2.description.AxisService;
|
||||
import org.apache.axis2.engine.ServiceLifeCycle;
|
||||
|
||||
<<<<<<< HEAD
|
||||
import com.cloud.bridge.service.ServiceProvider;
|
||||
=======
|
||||
import com.cloud.bridge.service.controller.s3.ServiceProvider;
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
/**
|
||||
* @author Kelven Yang
|
||||
|
|
|
|||
|
|
@ -18,8 +18,29 @@ package com.cloud.bridge.model;
|
|||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
<<<<<<< HEAD
|
||||
/**
|
||||
* @author Kelven Yang
|
||||
=======
|
||||
import com.cloud.bridge.service.exception.UnsupportedException;
|
||||
import com.cloud.bridge.util.OrderedPair;
|
||||
import com.cloud.bridge.util.Triple;
|
||||
|
||||
/**
|
||||
* @author John Zucker, Kelven Yang
|
||||
* A model of stored ACLs to remember the ACL permissions per canonicalUserID per grantee
|
||||
* Hold the AWS S3 grantee and permission constants.
|
||||
*
|
||||
* This class implements two forms of getCannedAccessControls mappings, as static methods,
|
||||
*
|
||||
* (a) an OrderedPair which provides a maplet across
|
||||
* < permission, grantee >
|
||||
* when given an aclRequestString and a target (i.e. bucket or object),
|
||||
*
|
||||
* (b) a Triplet
|
||||
* < permission1, permission2, symbol >
|
||||
* when given an aclRequestString, a target (i.e. bucket or object) and the ID of the owner.
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
*/
|
||||
public class SAcl implements Serializable {
|
||||
private static final long serialVersionUID = 7900837117165018850L;
|
||||
|
|
@ -28,7 +49,11 @@ public class SAcl implements Serializable {
|
|||
public static final int GRANTEE_ALLUSERS = 1;
|
||||
public static final int GRANTEE_AUTHENTICATED = 2;
|
||||
|
||||
<<<<<<< HEAD
|
||||
public static final int PERMISSION_PASS = -1; // -> no ACL test required
|
||||
=======
|
||||
public static final int PERMISSION_PASS = -1; // No ACL test required
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
public static final int PERMISSION_NONE = 0;
|
||||
public static final int PERMISSION_READ = 1;
|
||||
public static final int PERMISSION_WRITE = 2;
|
||||
|
|
@ -124,4 +149,103 @@ public class SAcl implements Serializable {
|
|||
public void setLastModifiedTime(Date lastModifiedTime) {
|
||||
this.lastModifiedTime = lastModifiedTime;
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
/** Return an OrderedPair
|
||||
* < permission, grantee >
|
||||
* comprising
|
||||
* a permission - which is one of SAcl.PERMISSION_PASS, SAcl.PERMISSION_NONE, SAcl.PERMISSION_READ,
|
||||
* SAcl.PERMISSION_WRITE, SAcl.PERMISSION_READ_ACL, SAcl.PERMISSION_WRITE_ACL, SAcl.PERMISSION_FULL
|
||||
* a grantee - which is one of GRANTEE_ALLUSERS, GRANTEE_AUTHENTICATED, GRANTEE_USER
|
||||
*
|
||||
* Access controls that are specified via the "x-amz-acl:" headers in REST requests for buckets.
|
||||
* The ACL request string is treated as a request for a known cannedAccessPolicy
|
||||
* @param aclRequestString - The requested ACL from the set of AWS S3 canned ACLs
|
||||
* @param target - Either "SBucket" or otherwise assumed to be for a single object item
|
||||
*/
|
||||
public static OrderedPair <Integer,Integer> getCannedAccessControls ( String aclRequestString, String target )
|
||||
throws UnsupportedException
|
||||
{
|
||||
if ( aclRequestString.equalsIgnoreCase( "public-read" ))
|
||||
// All users granted READ access.
|
||||
return new OrderedPair <Integer,Integer> (PERMISSION_READ,GRANTEE_ALLUSERS);
|
||||
else if (aclRequestString.equalsIgnoreCase( "public-read-write" ))
|
||||
// All users granted READ and WRITE access
|
||||
return new OrderedPair <Integer,Integer> ((PERMISSION_READ | PERMISSION_WRITE),GRANTEE_ALLUSERS);
|
||||
else if (aclRequestString.equalsIgnoreCase( "authenticated-read" ))
|
||||
// Authenticated users have READ access
|
||||
return new OrderedPair <Integer,Integer> (PERMISSION_READ,GRANTEE_AUTHENTICATED);
|
||||
else if (aclRequestString.equalsIgnoreCase( "private" ))
|
||||
// Only Owner gets FULL_CONTROL
|
||||
return new OrderedPair <Integer,Integer> (PERMISSION_FULL,GRANTEE_USER);
|
||||
else if (aclRequestString.equalsIgnoreCase( "bucket-owner-read" ))
|
||||
{
|
||||
// Object Owner gets FULL_CONTROL, Bucket Owner gets READ
|
||||
if ( target.equalsIgnoreCase( "SBucket" ))
|
||||
return new OrderedPair <Integer,Integer> (PERMISSION_READ, GRANTEE_USER);
|
||||
else
|
||||
return new OrderedPair <Integer,Integer> (PERMISSION_FULL, GRANTEE_USER);
|
||||
}
|
||||
else if (aclRequestString.equalsIgnoreCase( "bucket-owner-full-control" ))
|
||||
{
|
||||
// Object Owner gets FULL_CONTROL, Bucket Owner gets FULL_CONTROL
|
||||
// This is equivalent to private when used with PUT Bucket
|
||||
return new OrderedPair <Integer,Integer> (PERMISSION_FULL,GRANTEE_USER);
|
||||
}
|
||||
else throw new UnsupportedException( "Unknown Canned Access Policy: " + aclRequestString + " is not supported" );
|
||||
}
|
||||
|
||||
/** Return a Triple
|
||||
* < permission1, permission2, symbol >
|
||||
* comprising
|
||||
* two permissions - which is one of SAcl.PERMISSION_PASS, SAcl.PERMISSION_NONE, SAcl.PERMISSION_READ,
|
||||
* SAcl.PERMISSION_WRITE, SAcl.PERMISSION_READ_ACL, SAcl.PERMISSION_WRITE_ACL, SAcl.PERMISSION_FULL
|
||||
* permission1 applies to objects, permission2 applies to buckets.
|
||||
* a symbol to indicate whether the principal is anonymous (i.e. string "A") or authenticated user (i.e.
|
||||
* string "*") - otherwise null indicates a single ACL for all users.
|
||||
*
|
||||
* Access controls that are specified via the "x-amz-acl:" headers in REST requests for buckets.
|
||||
* The ACL request string is treated as a request for a known cannedAccessPolicy
|
||||
* @param aclRequestString - The requested ACL from the set of AWS S3 canned ACLs
|
||||
* @param target - Either "SBucket" or otherwise assumed to be for a single object item
|
||||
* @param ownerID - An ID for the owner, if used in place of symbols "A" or "*"
|
||||
*/
|
||||
public static Triple <Integer,Integer,String> getCannedAccessControls ( String aclRequestString, String target, String ownerID )
|
||||
throws UnsupportedException
|
||||
{
|
||||
if ( aclRequestString.equalsIgnoreCase( "public-read" ))
|
||||
// Owner gets FULL_CONTROL and the anonymous principal (the 'A' symbol here) is granted READ access.
|
||||
return new Triple <Integer, Integer, String> (PERMISSION_FULL, PERMISSION_READ,"A");
|
||||
else if (aclRequestString.equalsIgnoreCase( "public-read-write" ))
|
||||
// Owner gets FULL_CONTROL and the anonymous principal (the 'A' symbol here) is granted READ and WRITE access
|
||||
return new Triple <Integer, Integer, String> (PERMISSION_FULL, (PERMISSION_READ | PERMISSION_WRITE),"A");
|
||||
else if (aclRequestString.equalsIgnoreCase( "authenticated-read" ))
|
||||
// Owner gets FULL_CONTROL and ANY principal authenticated as a registered S3 user (the '*' symbol here) is granted READ access
|
||||
return new Triple <Integer, Integer, String> (PERMISSION_FULL, PERMISSION_READ,"*");
|
||||
else if (aclRequestString.equalsIgnoreCase( "private" ))
|
||||
// This is termed the "private" or default ACL, "Owner gets FULL_CONTROL"
|
||||
return new Triple <Integer, Integer, String> (PERMISSION_FULL, PERMISSION_FULL,null);
|
||||
else if (aclRequestString.equalsIgnoreCase( "bucket-owner-read" ))
|
||||
{
|
||||
// Object Owner gets FULL_CONTROL, Bucket Owner gets READ
|
||||
// This is equivalent to private when used with PUT Bucket
|
||||
if ( target.equalsIgnoreCase( "SBucket" ))
|
||||
return new Triple <Integer, Integer, String> (PERMISSION_FULL,PERMISSION_FULL ,null);
|
||||
else
|
||||
return new Triple <Integer, Integer, String> (PERMISSION_FULL,PERMISSION_READ,ownerID);
|
||||
}
|
||||
else if (aclRequestString.equalsIgnoreCase( "bucket-owner-full-control" ))
|
||||
{
|
||||
// Object Owner gets FULL_CONTROL, Bucket Owner gets FULL_CONTROL
|
||||
// This is equivalent to private when used with PUT Bucket
|
||||
if ( target.equalsIgnoreCase( "SBucket" ))
|
||||
return new Triple <Integer, Integer, String> (PERMISSION_FULL, PERMISSION_FULL, null);
|
||||
else
|
||||
return new Triple <Integer, Integer, String> (PERMISSION_FULL,PERMISSION_FULL, ownerID);
|
||||
}
|
||||
else throw new UnsupportedException( "Unknown Canned Access Policy: " + aclRequestString + " is not supported" );
|
||||
}
|
||||
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,12 +21,28 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
|
||||
/**
|
||||
<<<<<<< HEAD
|
||||
* @author Kelven Yang
|
||||
=======
|
||||
* @author Kelven Yang, John Zucker
|
||||
* Holds the relation
|
||||
* Id,
|
||||
* Name,
|
||||
* OwnerCanonicalId,
|
||||
* SHost,
|
||||
* CreateTime,
|
||||
* VersioningStatus
|
||||
* For ORM see "com/cloud/bridge/model/SHost.hbm.xml"
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
*/
|
||||
public class SBucket implements Serializable {
|
||||
private static final long serialVersionUID = 7430267766019671273L;
|
||||
|
||||
<<<<<<< HEAD
|
||||
public static final int VERSIONING_NULL = 0; // -> initial set, not set to anything yet
|
||||
=======
|
||||
public static final int VERSIONING_NULL = 0;
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
public static final int VERSIONING_ENABLED = 1;
|
||||
public static final int VERSIONING_SUSPENDED = 2;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,11 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
|
||||
/**
|
||||
<<<<<<< HEAD
|
||||
* @author Kelven Yang
|
||||
=======
|
||||
* @author Kelven Yang, John Zucker
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
*/
|
||||
public class SHost implements Serializable {
|
||||
private static final long serialVersionUID = 213346565810468018L;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,11 @@ import java.util.Iterator;
|
|||
import java.util.Set;
|
||||
|
||||
/**
|
||||
<<<<<<< HEAD
|
||||
* @author Kelven Yang
|
||||
=======
|
||||
* @author Kelven Yang, John Zucker
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
*/
|
||||
public class SObject implements Serializable {
|
||||
private static final long serialVersionUID = 8566744941395660486L;
|
||||
|
|
@ -33,7 +37,11 @@ public class SObject implements Serializable {
|
|||
private String ownerCanonicalId;
|
||||
|
||||
private int nextSequence;
|
||||
<<<<<<< HEAD
|
||||
private String deletionMark; // -> this must also a unique ID to give to the REST client
|
||||
=======
|
||||
private String deletionMark; // This must also a unique ID to give to the REST client
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
private Date createTime;
|
||||
|
||||
|
|
@ -133,7 +141,11 @@ public class SObject implements Serializable {
|
|||
{
|
||||
SObjectItem item = it.next();
|
||||
|
||||
<<<<<<< HEAD
|
||||
// -> If versioning is off then return the item with the null version string (if exists)
|
||||
=======
|
||||
// If versioning is off then return the item with the null version string (if exists)
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
// For example, the bucket could have allowed versioning and then it was suspended
|
||||
// If an application wants a specific version it will need to explicitly ask for it
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,11 @@ import java.io.Serializable;
|
|||
import java.util.Date;
|
||||
|
||||
/**
|
||||
<<<<<<< HEAD
|
||||
* @author Kelven Yang
|
||||
=======
|
||||
* @author Kelven Yang, John Zucker
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
*/
|
||||
public class SObjectItem implements Serializable {
|
||||
private static final long serialVersionUID = -7351173256185687851L;
|
||||
|
|
@ -76,7 +80,11 @@ public class SObjectItem implements Serializable {
|
|||
}
|
||||
|
||||
public void setStoredPath(String storedPath) {
|
||||
<<<<<<< HEAD
|
||||
this.storedPath = storedPath;
|
||||
=======
|
||||
this.storedPath = storedPath; // TODO - storedpath holds integer, called from S3Engine.allocObjectItem
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
||||
public long getStoredSize() {
|
||||
|
|
|
|||
|
|
@ -66,7 +66,11 @@ public class UserCredentials implements Serializable {
|
|||
|
||||
if (!(other instanceof UserCredentials)) return false;
|
||||
|
||||
<<<<<<< HEAD
|
||||
// -> the cert id can be null in both or either, since it is only used for the SOAP API
|
||||
=======
|
||||
// The cert id can be null. The cert is unused in the REST API.
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
if ( getAccessKey().equals(((UserCredentials)other).getAccessKey()) &&
|
||||
getSecretKey().equals(((UserCredentials)other).getSecretKey()))
|
||||
{
|
||||
|
|
@ -85,7 +89,11 @@ public class UserCredentials implements Serializable {
|
|||
int hashCode = 0;
|
||||
String thisCertId = getCertUniqueId();
|
||||
|
||||
<<<<<<< HEAD
|
||||
// -> the cert id can be null, since it is only used for the SOAP API
|
||||
=======
|
||||
// The cert id can be null. The cert is unused in the REST API.
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
hashCode = hashCode*17 + getAccessKey().hashCode();
|
||||
hashCode = hashCode*17 + getSecretKey().hashCode();
|
||||
if (null != thisCertId) hashCode = hashCode*17 + thisCertId.hashCode();
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import org.hibernate.Session;
|
|||
import com.cloud.bridge.util.QueryHelper;
|
||||
|
||||
/**
|
||||
<<<<<<< HEAD
|
||||
* @author Kelven Yang
|
||||
*/
|
||||
public class EntityDao<T> {
|
||||
|
|
@ -40,33 +41,72 @@ public class EntityDao<T> {
|
|||
this.isCloudStackSession = isCloudStackSession;
|
||||
// Note : beginTransaction can be called multiple times
|
||||
PersistContext.beginTransaction(isCloudStackSession);
|
||||
=======
|
||||
* @author Kelven Yang, John Zucker
|
||||
* Provide methods for getting, saving, deleting or updating state per session or, in a given session, returnin a List in
|
||||
* response to queryEntities for a particular instantation of the EntityDao generic class, as defined here.
|
||||
* Any instantation of EntityDao passes in the class for which it is instantiating. For example a new instance of SBucketDao
|
||||
* passes in com.cloud.bridge.model.SBucket as its clazz.
|
||||
*/
|
||||
|
||||
public class EntityDao<T> {
|
||||
private Class<?> clazz;
|
||||
|
||||
public EntityDao(Class<?> clazz) {
|
||||
this.clazz = clazz;
|
||||
|
||||
// Note : beginTransaction can be called multiple times
|
||||
// "If a new underlying transaction is required, begin the transaction. Otherwise continue the new work in the
|
||||
// context of the existing underlying transaction." from the Hibernate spec
|
||||
PersistContext.beginTransaction();
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T get(Serializable id) {
|
||||
<<<<<<< HEAD
|
||||
Session session = PersistContext.getSession(isCloudStackSession);
|
||||
=======
|
||||
Session session = PersistContext.getSession();
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
return (T)session.get(clazz, id);
|
||||
}
|
||||
|
||||
public T save(T entity) {
|
||||
<<<<<<< HEAD
|
||||
Session session = PersistContext.getSession(isCloudStackSession);
|
||||
=======
|
||||
Session session = PersistContext.getSession();
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
session.saveOrUpdate(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
public T update(T entity) {
|
||||
<<<<<<< HEAD
|
||||
Session session = PersistContext.getSession(isCloudStackSession);
|
||||
=======
|
||||
Session session = PersistContext.getSession();
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
session.saveOrUpdate(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
public void delete(T entity) {
|
||||
<<<<<<< HEAD
|
||||
Session session = PersistContext.getSession(isCloudStackSession);
|
||||
=======
|
||||
Session session = PersistContext.getSession();
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
session.delete(entity);
|
||||
}
|
||||
|
||||
public T queryEntity(String hql, Object[] params) {
|
||||
<<<<<<< HEAD
|
||||
Session session = PersistContext.getSession(isCloudStackSession);
|
||||
=======
|
||||
Session session = PersistContext.getSession();
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
Query query = session.createQuery(hql);
|
||||
query.setMaxResults(1);
|
||||
QueryHelper.bindParameters(query, params);
|
||||
|
|
@ -74,7 +114,11 @@ public class EntityDao<T> {
|
|||
}
|
||||
|
||||
public List<T> queryEntities(String hql, Object[] params) {
|
||||
<<<<<<< HEAD
|
||||
Session session = PersistContext.getSession(isCloudStackSession);
|
||||
=======
|
||||
Session session = PersistContext.getSession();
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
Query query = session.createQuery(hql);
|
||||
QueryHelper.bindParameters(query, params);
|
||||
|
||||
|
|
@ -82,7 +126,11 @@ public class EntityDao<T> {
|
|||
}
|
||||
|
||||
public List<T> queryEntities(String hql, int offset, int limit, Object[] params) {
|
||||
<<<<<<< HEAD
|
||||
Session session = PersistContext.getSession(isCloudStackSession);
|
||||
=======
|
||||
Session session = PersistContext.getSession();
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
Query query = session.createQuery(hql);
|
||||
QueryHelper.bindParameters(query, params);
|
||||
query.setFirstResult(offset);
|
||||
|
|
@ -91,7 +139,11 @@ public class EntityDao<T> {
|
|||
}
|
||||
|
||||
public int executeUpdate(String hql, Object[] params) {
|
||||
<<<<<<< HEAD
|
||||
Session session = PersistContext.getSession(isCloudStackSession);
|
||||
=======
|
||||
Session session = PersistContext.getSession();
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
Query query = session.createQuery(hql);
|
||||
QueryHelper.bindParameters(query, params);
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,12 @@ import org.hibernate.Session;
|
|||
import org.hibernate.Transaction;
|
||||
|
||||
import com.cloud.bridge.util.CloudSessionFactory;
|
||||
<<<<<<< HEAD
|
||||
import com.cloud.bridge.util.CloudStackSessionFactory;
|
||||
import com.cloud.bridge.util.Tuple;
|
||||
=======
|
||||
import com.cloud.bridge.util.OrderedPair;
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
/**
|
||||
* @author Kelven Yang
|
||||
|
|
@ -49,11 +53,16 @@ public class PersistContext {
|
|||
protected final static Logger logger = Logger.getLogger(PersistContext.class);
|
||||
|
||||
private static final CloudSessionFactory sessionFactory;
|
||||
<<<<<<< HEAD
|
||||
|
||||
=======
|
||||
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
private static final ThreadLocal<Session> threadSession = new ThreadLocal<Session>();
|
||||
private static final ThreadLocal<Transaction> threadTransaction = new ThreadLocal<Transaction>();
|
||||
private static final ThreadLocal<Map<String, Object>> threadStore = new ThreadLocal<Map<String, Object>>();
|
||||
|
||||
<<<<<<< HEAD
|
||||
private static final CloudStackSessionFactory cloudStackSessionFactory;
|
||||
private static final ThreadLocal<Session> threadCloudStackSession = new ThreadLocal<Session>();
|
||||
private static final ThreadLocal<Transaction> threadCloudStackTransaction = new ThreadLocal<Transaction>();
|
||||
|
|
@ -62,12 +71,18 @@ public class PersistContext {
|
|||
try {
|
||||
sessionFactory = CloudSessionFactory.getInstance();
|
||||
cloudStackSessionFactory = CloudStackSessionFactory.getInstance();
|
||||
=======
|
||||
static {
|
||||
try {
|
||||
sessionFactory = CloudSessionFactory.getInstance();
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
} catch(HibernateException e) {
|
||||
logger.error("Exception " + e.getMessage(), e);
|
||||
throw new PersistException(e);
|
||||
}
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
public static Session getSession(boolean cloudStackSession) {
|
||||
Session s = null;
|
||||
try {
|
||||
|
|
@ -135,12 +150,48 @@ public class PersistContext {
|
|||
}else{
|
||||
threadTransaction.set(tx);
|
||||
}
|
||||
=======
|
||||
public static Session getSession() {
|
||||
Session s = threadSession.get();
|
||||
try {
|
||||
if(s == null) {
|
||||
s = sessionFactory.openSession();
|
||||
threadSession.set(s);
|
||||
}
|
||||
} catch(HibernateException e) {
|
||||
logger.error("Exception " + e.getMessage(), e);
|
||||
throw new PersistException(e);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public static void closeSession() {
|
||||
try {
|
||||
Session s = (Session) threadSession.get();
|
||||
threadSession.set(null);
|
||||
|
||||
if (s != null && s.isOpen())
|
||||
s.close();
|
||||
} catch(HibernateException e) {
|
||||
logger.error("Exception " + e.getMessage(), e);
|
||||
throw new PersistException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void beginTransaction() {
|
||||
Transaction tx = threadTransaction.get();
|
||||
try {
|
||||
if (tx == null) {
|
||||
tx = getSession().beginTransaction();
|
||||
threadTransaction.set(tx);
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
} catch(HibernateException e) {
|
||||
logger.error("Exception " + e.getMessage(), e);
|
||||
throw new PersistException(e);
|
||||
}
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
|
||||
public static void beginTransaction() {
|
||||
beginTransaction(false);
|
||||
|
|
@ -168,10 +219,24 @@ public class PersistContext {
|
|||
logger.error("Exception " + e.getMessage(), e);
|
||||
|
||||
rollbackTransaction(cloudStackTxn);
|
||||
=======
|
||||
|
||||
public static void commitTransaction() {
|
||||
Transaction tx = threadTransaction.get();
|
||||
try {
|
||||
if ( tx != null && !tx.wasCommitted() && !tx.wasRolledBack() )
|
||||
tx.commit();
|
||||
threadTransaction.set(null);
|
||||
} catch (HibernateException e) {
|
||||
logger.error("Exception " + e.getMessage(), e);
|
||||
|
||||
rollbackTransaction();
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
throw new PersistException(e);
|
||||
}
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
public static void commitTransaction() {
|
||||
commitTransaction(false);
|
||||
}
|
||||
|
|
@ -187,6 +252,12 @@ public class PersistContext {
|
|||
threadTransaction.set(null);
|
||||
}
|
||||
try {
|
||||
=======
|
||||
public static void rollbackTransaction() {
|
||||
Transaction tx = (Transaction) threadTransaction.get();
|
||||
try {
|
||||
threadTransaction.set(null);
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
if ( tx != null && !tx.wasCommitted() && !tx.wasRolledBack() ) {
|
||||
tx.rollback();
|
||||
}
|
||||
|
|
@ -194,6 +265,7 @@ public class PersistContext {
|
|||
logger.error("Exception " + e.getMessage(), e);
|
||||
throw new PersistException(e);
|
||||
} finally {
|
||||
<<<<<<< HEAD
|
||||
closeSession(cloudStackTxn);
|
||||
}
|
||||
}
|
||||
|
|
@ -202,6 +274,12 @@ public class PersistContext {
|
|||
rollbackTransaction(false);
|
||||
}
|
||||
|
||||
=======
|
||||
closeSession();
|
||||
}
|
||||
}
|
||||
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
public static void flush() {
|
||||
commitTransaction();
|
||||
beginTransaction();
|
||||
|
|
@ -216,15 +294,24 @@ public class PersistContext {
|
|||
* @return
|
||||
*/
|
||||
public static boolean acquireNamedLock(String name, int timeoutSeconds) {
|
||||
<<<<<<< HEAD
|
||||
Connection conn = getJDBCConnection(name, true);
|
||||
if(conn == null) {
|
||||
=======
|
||||
Connection jdbcConnection = getJDBCConnection(name, true);
|
||||
if(jdbcConnection == null) {
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
logger.warn("Unable to acquire named lock connection for named lock: " + name);
|
||||
return false;
|
||||
}
|
||||
|
||||
PreparedStatement pstmt = null;
|
||||
try {
|
||||
<<<<<<< HEAD
|
||||
pstmt = conn.prepareStatement("SELECT COALESCE(GET_LOCK(?, ?),0)");
|
||||
=======
|
||||
pstmt = jdbcConnection.prepareStatement("SELECT COALESCE(GET_LOCK(?, ?),0)");
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
pstmt.setString(1, name);
|
||||
pstmt.setInt(2, timeoutSeconds);
|
||||
|
|
@ -256,15 +343,24 @@ public class PersistContext {
|
|||
}
|
||||
|
||||
public static boolean releaseNamedLock(String name) {
|
||||
<<<<<<< HEAD
|
||||
Connection conn = getJDBCConnection(name, false);
|
||||
if(conn == null) {
|
||||
=======
|
||||
Connection jdbcConnection = getJDBCConnection(name, false);
|
||||
if(jdbcConnection == null) {
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
logger.error("Unable to acquire DB connection for global lock system");
|
||||
return false;
|
||||
}
|
||||
|
||||
PreparedStatement pstmt = null;
|
||||
try {
|
||||
<<<<<<< HEAD
|
||||
pstmt = conn.prepareStatement("SELECT COALESCE(RELEASE_LOCK(?), 0)");
|
||||
=======
|
||||
pstmt = jdbcConnection.prepareStatement("SELECT COALESCE(RELEASE_LOCK(?), 0)");
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
pstmt.setString(1, name);
|
||||
ResultSet rs = pstmt.executeQuery();
|
||||
if(rs != null && rs.first())
|
||||
|
|
@ -283,7 +379,11 @@ public class PersistContext {
|
|||
@SuppressWarnings("deprecation")
|
||||
private static Connection getJDBCConnection(String name, boolean allocNew) {
|
||||
String registryKey = "JDBC-Connection." + name;
|
||||
<<<<<<< HEAD
|
||||
Tuple<Session, Connection> info = (Tuple<Session, Connection>)getThreadStoreObject(registryKey);
|
||||
=======
|
||||
OrderedPair<Session, Connection> info = (OrderedPair<Session, Connection>)getThreadStoreObject(registryKey);
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
if(info == null && allocNew) {
|
||||
Session session = sessionFactory.openSession();
|
||||
Connection connection = session.connection();
|
||||
|
|
@ -305,7 +405,11 @@ public class PersistContext {
|
|||
return null;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
registerThreadStoreObject(registryKey, new Tuple<Session, Connection>(session, connection));
|
||||
=======
|
||||
registerThreadStoreObject(registryKey, new OrderedPair<Session, Connection>(session, connection));
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
|
@ -317,7 +421,11 @@ public class PersistContext {
|
|||
|
||||
private static void releaseJDBCConnection(String name) {
|
||||
String registryKey = "JDBC-Connection." + name;
|
||||
<<<<<<< HEAD
|
||||
Tuple<Session, Connection> info = (Tuple<Session, Connection>)unregisterThreadStoreObject(registryKey);
|
||||
=======
|
||||
OrderedPair<Session, Connection> info = (OrderedPair<Session, Connection>)unregisterThreadStoreObject(registryKey);
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
if(info != null) {
|
||||
try {
|
||||
info.getSecond().close();
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import com.cloud.bridge.util.ConfigurationHelper;
|
|||
public class BucketPolicyDao {
|
||||
public static final Logger logger = Logger.getLogger(BucketPolicyDao.class);
|
||||
|
||||
<<<<<<< HEAD
|
||||
private Connection conn = null;
|
||||
private String dbName = null;
|
||||
private String dbUser = null;
|
||||
|
|
@ -43,6 +44,16 @@ public class BucketPolicyDao {
|
|||
public BucketPolicyDao()
|
||||
{
|
||||
File propertiesFile = ConfigurationHelper.findConfigurationFile("db.properties");
|
||||
=======
|
||||
private Connection jdbcConnection = null;
|
||||
private String dbName = null;
|
||||
private String dbUser = null;
|
||||
private String dbPassword = null;
|
||||
|
||||
public BucketPolicyDao()
|
||||
{
|
||||
File propertiesFile = ConfigurationHelper.findConfigurationFile("ec2-service.properties");
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
Properties EC2Prop = null;
|
||||
|
||||
if (null != propertiesFile) {
|
||||
|
|
@ -54,11 +65,17 @@ public class BucketPolicyDao {
|
|||
} catch (IOException e) {
|
||||
logger.warn("Unable to read properties file: " + propertiesFile.getAbsolutePath(), e);
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
dbHost = EC2Prop.getProperty( "db.cloud.host" );
|
||||
dbName = EC2Prop.getProperty( "db.awsapi.name" );
|
||||
dbUser = EC2Prop.getProperty( "db.cloud.username" );
|
||||
dbPassword = EC2Prop.getProperty( "db.cloud.password" );
|
||||
dbPort = EC2Prop.getProperty( "db.cloud.port" );
|
||||
=======
|
||||
dbName = EC2Prop.getProperty( "dbName" );
|
||||
dbUser = EC2Prop.getProperty( "dbUser" );
|
||||
dbPassword = EC2Prop.getProperty( "dbPassword" );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +86,11 @@ public class BucketPolicyDao {
|
|||
|
||||
openConnection();
|
||||
try {
|
||||
<<<<<<< HEAD
|
||||
statement = conn.prepareStatement ( "INSERT INTO bucket_policies (BucketName, OwnerCanonicalID, Policy) VALUES (?,?,?)" );
|
||||
=======
|
||||
statement = jdbcConnection.prepareStatement ( "INSERT INTO bucket_policies (BucketName, OwnerCanonicalID, Policy) VALUES (?,?,?)" );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
statement.setString( 1, bucketName );
|
||||
statement.setString( 2, owner );
|
||||
statement.setString( 3, policy );
|
||||
|
|
@ -93,7 +114,11 @@ public class BucketPolicyDao {
|
|||
|
||||
openConnection();
|
||||
try {
|
||||
<<<<<<< HEAD
|
||||
statement = conn.prepareStatement ( "SELECT OwnerCanonicalID FROM bucket_policies WHERE BucketName=?" );
|
||||
=======
|
||||
statement = jdbcConnection.prepareStatement ( "SELECT OwnerCanonicalID FROM bucket_policies WHERE BucketName=?" );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
statement.setString( 1, bucketName );
|
||||
ResultSet rs = statement.executeQuery();
|
||||
if (rs.next()) owner = rs.getString( "OwnerCanonicalID" );
|
||||
|
|
@ -113,7 +138,11 @@ public class BucketPolicyDao {
|
|||
|
||||
openConnection();
|
||||
try {
|
||||
<<<<<<< HEAD
|
||||
statement = conn.prepareStatement ( "SELECT Policy FROM bucket_policies WHERE BucketName=?" );
|
||||
=======
|
||||
statement = jdbcConnection.prepareStatement ( "SELECT Policy FROM bucket_policies WHERE BucketName=?" );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
statement.setString( 1, bucketName );
|
||||
ResultSet rs = statement.executeQuery();
|
||||
if (rs.next()) policy = rs.getString( "Policy" );
|
||||
|
|
@ -132,7 +161,11 @@ public class BucketPolicyDao {
|
|||
|
||||
openConnection();
|
||||
try {
|
||||
<<<<<<< HEAD
|
||||
statement = conn.prepareStatement ( "DELETE FROM bucket_policies WHERE BucketName=?" );
|
||||
=======
|
||||
statement = jdbcConnection.prepareStatement ( "DELETE FROM bucket_policies WHERE BucketName=?" );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
statement.setString( 1, bucketName );
|
||||
int count = statement.executeUpdate();
|
||||
statement.close();
|
||||
|
|
@ -145,14 +178,25 @@ public class BucketPolicyDao {
|
|||
private void openConnection()
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
if (null == conn) {
|
||||
Class.forName( "com.mysql.jdbc.Driver" ).newInstance();
|
||||
conn = DriverManager.getConnection( "jdbc:mysql://" + dbHost + ":" + dbPort + "/" + dbName, dbUser, dbPassword );
|
||||
=======
|
||||
if (null == jdbcConnection) {
|
||||
Class.forName( "com.mysql.jdbc.Driver" ).newInstance();
|
||||
jdbcConnection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/"+dbName, dbUser, dbPassword );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
}
|
||||
|
||||
private void closeConnection() throws SQLException {
|
||||
<<<<<<< HEAD
|
||||
if (null != conn) conn.close();
|
||||
conn = null;
|
||||
=======
|
||||
if (null != jdbcConnection) jdbcConnection.close();
|
||||
jdbcConnection = null;
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,11 @@ import com.cloud.bridge.service.core.s3.S3MetaDataEntry;
|
|||
import com.cloud.bridge.service.core.s3.S3MultipartPart;
|
||||
import com.cloud.bridge.service.core.s3.S3MultipartUpload;
|
||||
import com.cloud.bridge.util.ConfigurationHelper;
|
||||
<<<<<<< HEAD
|
||||
import com.cloud.bridge.util.Tuple;
|
||||
=======
|
||||
import com.cloud.bridge.util.OrderedPair;
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
public class MultipartLoadDao {
|
||||
public static final Logger logger = Logger.getLogger(MultipartLoadDao.class);
|
||||
|
|
@ -46,12 +50,21 @@ public class MultipartLoadDao {
|
|||
private String dbName = null;
|
||||
private String dbUser = null;
|
||||
private String dbPassword = null;
|
||||
<<<<<<< HEAD
|
||||
private String dbHost = null;
|
||||
private String dbPort = null;
|
||||
|
||||
public MultipartLoadDao() {
|
||||
File propertiesFile = ConfigurationHelper.findConfigurationFile("db.properties");
|
||||
Properties EC2Prop = null;
|
||||
=======
|
||||
|
||||
public MultipartLoadDao() {
|
||||
File propertiesFile = ConfigurationHelper.findConfigurationFile("ec2-service.properties");
|
||||
Properties EC2Prop = null;
|
||||
|
||||
// The settings for the CLOUDBRIDGE database are shared with the EC2 API
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
if (null != propertiesFile) {
|
||||
EC2Prop = new Properties();
|
||||
|
|
@ -62,11 +75,17 @@ public class MultipartLoadDao {
|
|||
} catch (IOException e) {
|
||||
logger.warn("Unable to read properties file: " + propertiesFile.getAbsolutePath(), e);
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
dbHost = EC2Prop.getProperty( "db.cloud.host" );
|
||||
dbName = EC2Prop.getProperty( "db.awsapi.name" );
|
||||
dbUser = EC2Prop.getProperty( "db.cloud.username" );
|
||||
dbPassword = EC2Prop.getProperty( "db.cloud.password" );
|
||||
dbPort = EC2Prop.getProperty( "db.cloud.port" );
|
||||
=======
|
||||
dbName = EC2Prop.getProperty( "dbName" );
|
||||
dbUser = EC2Prop.getProperty( "dbUser" );
|
||||
dbPassword = EC2Prop.getProperty( "dbPassword" );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -78,7 +97,11 @@ public class MultipartLoadDao {
|
|||
* @return creator of the multipart upload, and NameKey of upload
|
||||
* @throws SQLException, ClassNotFoundException, IllegalAccessException, InstantiationException
|
||||
*/
|
||||
<<<<<<< HEAD
|
||||
public Tuple<String,String> multipartExits( int uploadId )
|
||||
=======
|
||||
public OrderedPair<String,String> multipartExits( int uploadId )
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException
|
||||
{
|
||||
PreparedStatement statement = null;
|
||||
|
|
@ -93,7 +116,11 @@ public class MultipartLoadDao {
|
|||
if ( rs.next()) {
|
||||
accessKey = rs.getString( "AccessKey" );
|
||||
nameKey = rs.getString( "NameKey" );
|
||||
<<<<<<< HEAD
|
||||
return new Tuple<String,String>( accessKey, nameKey );
|
||||
=======
|
||||
return new OrderedPair<String,String>( accessKey, nameKey );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
else return null;
|
||||
|
||||
|
|
@ -338,10 +365,17 @@ public class MultipartLoadDao {
|
|||
* @param prefix - can be null
|
||||
* @param keyMarker - can be null
|
||||
* @param uploadIdMarker - can be null, should only be defined if keyMarker is not-null
|
||||
<<<<<<< HEAD
|
||||
* @return Tuple<S3MultipartUpload[], isTruncated>
|
||||
* @throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException
|
||||
*/
|
||||
public Tuple<S3MultipartUpload[],Boolean> getInitiatedUploads( String bucketName, int maxParts, String prefix, String keyMarker, String uploadIdMarker )
|
||||
=======
|
||||
* @return OrderedPair<S3MultipartUpload[], isTruncated>
|
||||
* @throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException
|
||||
*/
|
||||
public OrderedPair<S3MultipartUpload[],Boolean> getInitiatedUploads( String bucketName, int maxParts, String prefix, String keyMarker, String uploadIdMarker )
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException
|
||||
{
|
||||
S3MultipartUpload[] inProgress = new S3MultipartUpload[maxParts];
|
||||
|
|
@ -387,7 +421,11 @@ public class MultipartLoadDao {
|
|||
statement.close();
|
||||
|
||||
if (i < maxParts) inProgress = (S3MultipartUpload[])resizeArray(inProgress,i);
|
||||
<<<<<<< HEAD
|
||||
return new Tuple<S3MultipartUpload[], Boolean>(inProgress, isTruncated);
|
||||
=======
|
||||
return new OrderedPair<S3MultipartUpload[], Boolean>(inProgress, isTruncated);
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
} finally {
|
||||
closeConnection();
|
||||
|
|
@ -432,7 +470,11 @@ public class MultipartLoadDao {
|
|||
|
||||
parts[i] = new S3MultipartPart();
|
||||
parts[i].setPartNumber( rs.getInt( "partNumber" ));
|
||||
<<<<<<< HEAD
|
||||
parts[i].setEtag( rs.getString( "MD5" ));
|
||||
=======
|
||||
parts[i].setEtag( rs.getString( "MD5" ).toLowerCase());
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
parts[i].setLastModified( tod );
|
||||
parts[i].setSize( rs.getInt( "StoredSize" ));
|
||||
parts[i].setPath( rs.getString( "StoredPath" ));
|
||||
|
|
@ -514,7 +556,11 @@ public class MultipartLoadDao {
|
|||
throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException {
|
||||
if (null == conn) {
|
||||
Class.forName( "com.mysql.jdbc.Driver" ).newInstance();
|
||||
<<<<<<< HEAD
|
||||
conn = DriverManager.getConnection( "jdbc:mysql://" + dbHost + ":" + dbPort + "/" + dbName, dbUser, dbPassword );
|
||||
=======
|
||||
conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/"+dbName, dbUser, dbPassword );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import org.apache.log4j.Logger;
|
|||
|
||||
import com.cloud.bridge.util.ConfigurationHelper;
|
||||
|
||||
<<<<<<< HEAD
|
||||
|
||||
public class OfferingDao extends BaseDao {
|
||||
public static final Logger logger = Logger.getLogger(OfferingDao.class);
|
||||
|
|
@ -38,6 +39,36 @@ public class OfferingDao extends BaseDao {
|
|||
|
||||
public OfferingDao()
|
||||
{
|
||||
=======
|
||||
public class OfferingDao {
|
||||
public static final Logger logger = Logger.getLogger(OfferingDao.class);
|
||||
|
||||
private Connection conn = null;
|
||||
private String dbName = null;
|
||||
private String dbUser = null;
|
||||
private String dbPassword = null;
|
||||
|
||||
public OfferingDao()
|
||||
{
|
||||
File propertiesFile = ConfigurationHelper.findConfigurationFile("ec2-service.properties");
|
||||
Properties EC2Prop = null;
|
||||
|
||||
// The settings for the CLOUDBRIDGE database are shared with the EC2 API
|
||||
|
||||
if (null != propertiesFile) {
|
||||
EC2Prop = new Properties();
|
||||
try {
|
||||
EC2Prop.load( new FileInputStream( propertiesFile ));
|
||||
} catch (FileNotFoundException e) {
|
||||
logger.warn("Unable to open properties file: " + propertiesFile.getAbsolutePath(), e);
|
||||
} catch (IOException e) {
|
||||
logger.warn("Unable to read properties file: " + propertiesFile.getAbsolutePath(), e);
|
||||
}
|
||||
dbName = EC2Prop.getProperty( "dbName" );
|
||||
dbUser = EC2Prop.getProperty( "dbUser" );
|
||||
dbPassword = EC2Prop.getProperty( "dbPassword" );
|
||||
}
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
||||
public int getOfferingCount()
|
||||
|
|
@ -155,7 +186,11 @@ public class OfferingDao extends BaseDao {
|
|||
{
|
||||
if (null == conn) {
|
||||
Class.forName( "com.mysql.jdbc.Driver" ).newInstance();
|
||||
<<<<<<< HEAD
|
||||
conn = DriverManager.getConnection( "jdbc:mysql://" + dbHost + ":" + dbPort + "/" + awsapi_dbName, dbUser, dbPassword );
|
||||
=======
|
||||
conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/"+dbName, dbUser, dbPassword );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,11 @@ import com.cloud.bridge.persist.PersistContext;
|
|||
import com.cloud.bridge.service.core.s3.S3MetaDataEntry;
|
||||
|
||||
/**
|
||||
<<<<<<< HEAD
|
||||
* @author Kelven Yang
|
||||
=======
|
||||
* @author Kelven Yang, John Zucker
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
*/
|
||||
public class SMetaDao extends EntityDao<SMeta> {
|
||||
public SMetaDao() {
|
||||
|
|
@ -46,7 +50,11 @@ public class SMetaDao extends EntityDao<SMeta> {
|
|||
}
|
||||
|
||||
public void save(String target, long targetId, S3MetaDataEntry[] entries) {
|
||||
<<<<<<< HEAD
|
||||
// -> the target's meta data are being redefined
|
||||
=======
|
||||
// To redefine the target's metadaa
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
executeUpdate("delete from SMeta where target=? and targetId=?", new Object[] { target, new Long(targetId)});
|
||||
|
||||
if(entries != null) {
|
||||
|
|
|
|||
|
|
@ -15,13 +15,23 @@
|
|||
*/
|
||||
package com.cloud.bridge.persist.dao;
|
||||
|
||||
<<<<<<< HEAD
|
||||
import java.sql.*;
|
||||
|
||||
=======
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.sql.*;
|
||||
import java.util.Properties;
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.bridge.model.UserCredentials;
|
||||
import com.cloud.bridge.service.exception.NoSuchObjectException;
|
||||
<<<<<<< HEAD
|
||||
|
||||
|
||||
public class UserCredentialsDao extends BaseDao {
|
||||
|
|
@ -30,6 +40,40 @@ public class UserCredentialsDao extends BaseDao {
|
|||
private Connection conn = null;
|
||||
|
||||
public UserCredentialsDao() {
|
||||
=======
|
||||
import com.cloud.bridge.util.ConfigurationHelper;
|
||||
|
||||
|
||||
public class UserCredentialsDao {
|
||||
public static final Logger logger = Logger.getLogger(UserCredentialsDao.class);
|
||||
|
||||
private Connection conn = null;
|
||||
private String dbName = null;
|
||||
private String dbHost = null;
|
||||
private String dbUser = null;
|
||||
private String dbPassword = null;
|
||||
|
||||
public UserCredentialsDao() {
|
||||
File propertiesFile = ConfigurationHelper.findConfigurationFile("ec2-service.properties");
|
||||
Properties EC2Prop = null;
|
||||
|
||||
// The settings for the CLOUDBRIDGE database are shared with the EC2 API
|
||||
|
||||
if (null != propertiesFile) {
|
||||
EC2Prop = new Properties();
|
||||
try {
|
||||
EC2Prop.load( new FileInputStream( propertiesFile ));
|
||||
} catch (FileNotFoundException e) {
|
||||
logger.warn("Unable to open properties file: " + propertiesFile.getAbsolutePath(), e);
|
||||
} catch (IOException e) {
|
||||
logger.warn("Unable to read properties file: " + propertiesFile.getAbsolutePath(), e);
|
||||
}
|
||||
dbHost = EC2Prop.getProperty( "dbHost" );
|
||||
dbName = EC2Prop.getProperty( "dbName" );
|
||||
dbUser = EC2Prop.getProperty( "dbUser" );
|
||||
dbPassword = EC2Prop.getProperty( "dbPassword" );
|
||||
}
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
||||
public void setUserKeys( String cloudAccessKey, String cloudSecretKey )
|
||||
|
|
@ -131,7 +175,11 @@ public class UserCredentialsDao extends BaseDao {
|
|||
throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException {
|
||||
if (null == conn) {
|
||||
Class.forName( "com.mysql.jdbc.Driver" ).newInstance();
|
||||
<<<<<<< HEAD
|
||||
conn = DriverManager.getConnection( "jdbc:mysql://" + dbHost + "/" + awsapi_dbName, dbUser, dbPassword );
|
||||
=======
|
||||
conn = DriverManager.getConnection( "jdbc:mysql://" + dbHost + "/" + dbName, dbUser, dbPassword );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,11 @@ import javax.servlet.http.HttpServlet;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
<<<<<<< HEAD
|
||||
import com.cloud.bridge.persist.PersistContext;
|
||||
import com.cloud.bridge.persist.dao.CloudStackConfigurationDao;
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
import com.cloud.bridge.persist.dao.UserCredentialsDao;
|
||||
import com.cloud.bridge.util.ConfigurationHelper;
|
||||
|
||||
|
|
@ -20,14 +23,18 @@ public class EC2MainServlet extends HttpServlet{
|
|||
|
||||
public static final String EC2_REST_SERVLET_PATH="/rest/AmazonEC2/";
|
||||
public static final String EC2_SOAP_SERVLET_PATH="/services/AmazonEC2/";
|
||||
<<<<<<< HEAD
|
||||
public static final String ENABLE_EC2_API="enable.ec2.api";
|
||||
private static boolean isEC2APIEnabled = false;
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
/**
|
||||
* We build the path to where the keystore holding the WS-Security X509 certificates
|
||||
* are stored.
|
||||
*/
|
||||
public void init( ServletConfig config ) throws ServletException {
|
||||
<<<<<<< HEAD
|
||||
try{
|
||||
ConfigurationHelper.preConfigureConfigPathFromServletContext(config.getServletContext());
|
||||
UserCredentialsDao.preCheckTableExistence();
|
||||
|
|
@ -42,6 +49,10 @@ public class EC2MainServlet extends HttpServlet{
|
|||
PersistContext.closeSession(true);
|
||||
}
|
||||
|
||||
=======
|
||||
ConfigurationHelper.preConfigureConfigPathFromServletContext(config.getServletContext());
|
||||
UserCredentialsDao.preCheckTableExistence();
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
|
||||
|
|
@ -53,6 +64,7 @@ public class EC2MainServlet extends HttpServlet{
|
|||
}
|
||||
|
||||
protected void doGetOrPost(HttpServletRequest request, HttpServletResponse response) {
|
||||
<<<<<<< HEAD
|
||||
String action = request.getParameter( "Action" );
|
||||
|
||||
if(!isEC2APIEnabled){
|
||||
|
|
@ -60,6 +72,10 @@ public class EC2MainServlet extends HttpServlet{
|
|||
}
|
||||
|
||||
if(action != null){
|
||||
=======
|
||||
String action = request.getParameter( "Action" );
|
||||
if(action!=null){
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
//We presume it's a Query/Rest call
|
||||
try {
|
||||
RequestDispatcher dispatcher = request.getRequestDispatcher(EC2_REST_SERVLET_PATH);
|
||||
|
|
|
|||
|
|
@ -93,9 +93,15 @@ import com.amazon.ec2.StartInstancesResponse;
|
|||
import com.amazon.ec2.StopInstancesResponse;
|
||||
import com.amazon.ec2.TerminateInstancesResponse;
|
||||
import com.cloud.bridge.model.UserCredentials;
|
||||
<<<<<<< HEAD
|
||||
import com.cloud.bridge.persist.PersistContext;
|
||||
import com.cloud.bridge.persist.dao.OfferingDao;
|
||||
import com.cloud.bridge.persist.dao.UserCredentialsDao;
|
||||
=======
|
||||
import com.cloud.bridge.persist.dao.OfferingDao;
|
||||
import com.cloud.bridge.persist.dao.UserCredentialsDao;
|
||||
import com.cloud.bridge.service.controller.s3.ServiceProvider;
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
import com.cloud.bridge.service.core.ec2.EC2AssociateAddress;
|
||||
import com.cloud.bridge.service.core.ec2.EC2AuthorizeRevokeSecurityGroup;
|
||||
import com.cloud.bridge.service.core.ec2.EC2CreateImage;
|
||||
|
|
@ -136,7 +142,10 @@ import com.cloud.bridge.service.exception.EC2ServiceException.ClientError;
|
|||
import com.cloud.bridge.util.AuthenticationUtils;
|
||||
import com.cloud.bridge.util.ConfigurationHelper;
|
||||
import com.cloud.bridge.util.EC2RestAuth;
|
||||
<<<<<<< HEAD
|
||||
import com.cloud.stack.models.CloudStackAccount;
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
|
||||
public class EC2RestServlet extends HttpServlet {
|
||||
|
|
@ -151,7 +160,10 @@ public class EC2RestServlet extends HttpServlet {
|
|||
private String pathToKeystore = null;
|
||||
private String keystorePassword = null;
|
||||
private String wsdlVersion = null;
|
||||
<<<<<<< HEAD
|
||||
private String version = null;
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
boolean debug=true;
|
||||
|
||||
|
|
@ -178,7 +190,10 @@ public class EC2RestServlet extends HttpServlet {
|
|||
String keystore = EC2Prop.getProperty( "keystore" );
|
||||
keystorePassword = EC2Prop.getProperty( "keystorePass" );
|
||||
wsdlVersion = EC2Prop.getProperty( "WSDLVersion", "2009-11-30" );
|
||||
<<<<<<< HEAD
|
||||
version = EC2Prop.getProperty( "cloudbridgeVersion", "UNKNOWN VERSION" );
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
String installedPath = System.getenv("CATALINA_HOME");
|
||||
if (installedPath == null) installedPath = System.getenv("CATALINA_BASE");
|
||||
|
|
@ -275,9 +290,13 @@ public class EC2RestServlet extends HttpServlet {
|
|||
logger.error("Unsupported action " + action);
|
||||
throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available");
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
PersistContext.commitTransaction();
|
||||
PersistContext.commitTransaction(true);
|
||||
|
||||
=======
|
||||
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
} catch( EC2ServiceException e ) {
|
||||
response.setStatus(e.getErrorCode());
|
||||
|
||||
|
|
@ -303,8 +322,11 @@ public class EC2RestServlet extends HttpServlet {
|
|||
} catch (IOException e) {
|
||||
logger.error("Unexpected exception " + e.getMessage(), e);
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
PersistContext.closeSession();
|
||||
PersistContext.closeSession(true);
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -314,9 +336,15 @@ public class EC2RestServlet extends HttpServlet {
|
|||
* This is an unauthenticated REST call.
|
||||
*/
|
||||
private void cloudEC2Version( HttpServletRequest request, HttpServletResponse response ) {
|
||||
<<<<<<< HEAD
|
||||
String version_response = new String( "<?xml version=\"1.0\" encoding=\"utf-8\"?><CloudEC2Version>" + version + "</CloudEC2Version>" );
|
||||
response.setStatus(200);
|
||||
endResponse(response, version_response);
|
||||
=======
|
||||
String version = new String( "<?xml version=\"1.0\" encoding=\"utf-8\"?><CloudEC2Version>1.03</CloudEC2Version>" );
|
||||
response.setStatus(200);
|
||||
endResponse(response, version);
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -525,6 +553,7 @@ public class EC2RestServlet extends HttpServlet {
|
|||
endResponse(response, "SetOfferMapping exception " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
|
||||
// validate account is admin level
|
||||
try {
|
||||
|
|
@ -542,6 +571,8 @@ public class EC2RestServlet extends HttpServlet {
|
|||
endResponse(response, e.toString());
|
||||
return;
|
||||
}
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
try {
|
||||
OfferingDao ofDao = new OfferingDao();
|
||||
|
|
@ -574,6 +605,7 @@ public class EC2RestServlet extends HttpServlet {
|
|||
endResponse(response, "DeleteOfferMapping exception " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
|
||||
// validate account is admin level
|
||||
try {
|
||||
|
|
@ -591,6 +623,8 @@ public class EC2RestServlet extends HttpServlet {
|
|||
endResponse(response, e.toString());
|
||||
return;
|
||||
}
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
try {
|
||||
OfferingDao ofDao = new OfferingDao();
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ package com.cloud.bridge.service;
|
|||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.amazon.ec2.*;
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
import com.cloud.bridge.service.controller.s3.ServiceProvider;
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
public class EC2SoapService implements AmazonEC2SkeletonInterface {
|
||||
protected final static Logger logger = Logger.getLogger(EC2SoapService.class);
|
||||
|
|
|
|||
|
|
@ -1606,6 +1606,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface {
|
|||
EC2Snapshot[] snaps = engineResponse.getSnapshotSet();
|
||||
for (EC2Snapshot snap : snaps) {
|
||||
DescribeSnapshotsSetItemResponseType param3 = new DescribeSnapshotsSetItemResponseType();
|
||||
<<<<<<< HEAD
|
||||
param3.setSnapshotId( snap.getId());
|
||||
param3.setVolumeId( snap.getVolumeId());
|
||||
|
||||
|
|
@ -1627,6 +1628,15 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface {
|
|||
// param3.setStatus( snap.getState());
|
||||
|
||||
String ownerId = snap.getDomainId() + ":" + snap.getAccountName();
|
||||
=======
|
||||
param3.setSnapshotId( snap.getId().toString());
|
||||
param3.setVolumeId( snap.getVolumeId().toString());
|
||||
param3.setStatus( snap.getState());
|
||||
|
||||
String accountName = snap.getAccountName();
|
||||
String domainId = snap.getDomainId().toString();
|
||||
String ownerId = domainId + ":" + accountName;
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
// -> CloudStack seems to have issues with timestamp formats so just in case
|
||||
Calendar cal = snap.getCreated();
|
||||
|
|
@ -1636,10 +1646,19 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface {
|
|||
}
|
||||
param3.setStartTime( cal );
|
||||
|
||||
<<<<<<< HEAD
|
||||
param3.setOwnerId(ownerId);
|
||||
param3.setVolumeSize( snap.getVolumeSize().toString());
|
||||
param3.setDescription( snap.getName());
|
||||
param3.setOwnerAlias( snap.getAccountName() );
|
||||
=======
|
||||
param3.setProgress( "" );
|
||||
param3.setOwnerId(ownerId);
|
||||
Long volSize = new Long( snap.getVolumeSize());
|
||||
param3.setVolumeSize( volSize.toString());
|
||||
param3.setDescription( snap.getName());
|
||||
param3.setOwnerAlias( "" );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
ResourceTagSetType param18 = new ResourceTagSetType();
|
||||
ResourceTagSetItemType param19 = new ResourceTagSetItemType();
|
||||
|
|
|
|||
|
|
@ -22,4 +22,9 @@ package com.cloud.bridge.service;
|
|||
public interface S3Constants {
|
||||
public final String BUCKET_ATTR_KEY = "s3-bucket";
|
||||
public final String OBJECT_ATTR_KEY = "s3-object-key";
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
public final String PLAIN_POST_ACCESS_KEY = "s3-access-key";
|
||||
public final String PLAIN_POST_SIGNATURE = "s3-signature";
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
/*
|
||||
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved.
|
||||
*
|
||||
|
|
@ -761,3 +762,843 @@ public class S3RestServlet extends HttpServlet {
|
|||
}
|
||||
}
|
||||
}
|
||||
=======
|
||||
/*
|
||||
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.cloud.bridge.service;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.SignatureException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.bind.*;
|
||||
|
||||
import org.apache.axis2.AxisFault;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import com.cloud.bridge.io.MultiPartDimeInputStream;
|
||||
import com.cloud.bridge.model.SAcl;
|
||||
import com.cloud.bridge.persist.PersistContext;
|
||||
import com.cloud.bridge.persist.dao.UserCredentialsDao;
|
||||
import com.cloud.bridge.service.controller.s3.S3BucketAction;
|
||||
import com.cloud.bridge.service.controller.s3.S3ObjectAction;
|
||||
import com.cloud.bridge.service.controller.s3.ServiceProvider;
|
||||
import com.cloud.bridge.service.controller.s3.ServletAction;
|
||||
import com.cloud.bridge.service.core.s3.S3AccessControlList;
|
||||
import com.cloud.bridge.service.core.s3.S3AuthParams;
|
||||
import com.cloud.bridge.service.core.s3.S3Engine;
|
||||
import com.cloud.bridge.service.core.s3.S3Grant;
|
||||
import com.cloud.bridge.service.core.s3.S3MetaDataEntry;
|
||||
import com.cloud.bridge.service.core.s3.S3PutObjectRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3PutObjectResponse;
|
||||
import com.cloud.bridge.service.exception.InternalErrorException;
|
||||
import com.cloud.bridge.service.exception.InvalidBucketName;
|
||||
import com.cloud.bridge.service.exception.NoSuchObjectException;
|
||||
import com.cloud.bridge.service.exception.PermissionDeniedException;
|
||||
import com.cloud.bridge.util.AuthenticationUtils;
|
||||
import com.cloud.bridge.util.HeaderParam;
|
||||
import com.cloud.bridge.util.RestAuth;
|
||||
import com.cloud.bridge.util.S3SoapAuth;
|
||||
|
||||
/**
|
||||
* @author Kelven Yang, Mark Joseph, John Zucker
|
||||
*/
|
||||
public class S3RestServlet extends HttpServlet {
|
||||
private static final long serialVersionUID = -6168996266762804877L;
|
||||
|
||||
public static final Logger logger = Logger.getLogger(S3RestServlet.class);
|
||||
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
|
||||
processRequest( req, resp, "GET" );
|
||||
}
|
||||
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
|
||||
{
|
||||
// -> DIME requests are authenticated via the SOAP auth mechanism
|
||||
String type = req.getHeader( "Content-Type" );
|
||||
if ( null != type && type.equalsIgnoreCase( "application/dime" ))
|
||||
processDimeRequest(req, resp);
|
||||
else processRequest( req, resp, "POST" );
|
||||
}
|
||||
|
||||
protected void doPut(HttpServletRequest req, HttpServletResponse resp) {
|
||||
processRequest( req, resp, "PUT" );
|
||||
}
|
||||
|
||||
protected void doHead(HttpServletRequest req, HttpServletResponse resp) {
|
||||
processRequest( req, resp, "HEAD" );
|
||||
}
|
||||
|
||||
protected void doOptions(HttpServletRequest req, HttpServletResponse resp) {
|
||||
processRequest( req, resp, "OPTIONS" );
|
||||
}
|
||||
|
||||
protected void doDelete( HttpServletRequest req, HttpServletResponse resp ) {
|
||||
processRequest( req, resp, "DELETE" );
|
||||
}
|
||||
|
||||
/**
|
||||
* POST requests do not get authenticated on entry. The associated
|
||||
* access key and signature headers are embedded in the message not encoded
|
||||
* as HTTP headers.
|
||||
*/
|
||||
private void processRequest( HttpServletRequest request, HttpServletResponse response, String method )
|
||||
{
|
||||
try {
|
||||
logRequest(request);
|
||||
|
||||
// Our extensions to the S3 REST API for simple management actions
|
||||
// are conveyed with Request parameter CloudAction.
|
||||
// The present extensions are either to set up the user credentials
|
||||
// (see the cloud-bridge-register script for more detail) or
|
||||
// to report our version of this capability.
|
||||
// -> unauthenticated calls, should still be done over HTTPS
|
||||
String cloudAction = request.getParameter( "CloudAction" );
|
||||
if (null != cloudAction)
|
||||
{
|
||||
if (cloudAction.equalsIgnoreCase( "SetUserKeys" )) {
|
||||
setUserKeys(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cloudAction.equalsIgnoreCase( "SetCertificate" ))
|
||||
// At present a noop
|
||||
return;
|
||||
|
||||
if (cloudAction.equalsIgnoreCase( "CloudS3Version" )) {
|
||||
cloudS3Version(request, response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -> authenticated calls
|
||||
if (!method.equalsIgnoreCase( "POST" )) {
|
||||
S3AuthParams params = extractRequestHeaders( request );
|
||||
authenticateRequest( request, params );
|
||||
}
|
||||
|
||||
ServletAction action = routeRequest(request);
|
||||
if ( action != null ) {
|
||||
action.execute(request, response);
|
||||
}
|
||||
else {
|
||||
response.setStatus(404);
|
||||
endResponse(response, "File not found");
|
||||
}
|
||||
|
||||
PersistContext.commitTransaction();
|
||||
|
||||
}
|
||||
catch( InvalidBucketName e) {
|
||||
logger.error("Unexpected exception " + e.getMessage(), e);
|
||||
response.setStatus(400);
|
||||
endResponse(response, "Invalid Bucket Name - " + e.toString());
|
||||
}
|
||||
catch(PermissionDeniedException e) {
|
||||
logger.error("Unexpected exception " + e.getMessage(), e);
|
||||
response.setStatus(403);
|
||||
endResponse(response, "Access denied - " + e.toString());
|
||||
}
|
||||
catch(Throwable e) {
|
||||
logger.error("Unexpected exception " + e.getMessage(), e);
|
||||
response.setStatus(400);
|
||||
endResponse(response, "Bad request");
|
||||
|
||||
} finally {
|
||||
try {
|
||||
response.flushBuffer();
|
||||
} catch (IOException e) {
|
||||
logger.error("Unexpected exception " + e.getMessage(), e);
|
||||
}
|
||||
PersistContext.closeSession();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide an easy way to determine the version of the implementation running.
|
||||
*
|
||||
* This is an unauthenticated REST call.
|
||||
*/
|
||||
private void cloudS3Version( HttpServletRequest request, HttpServletResponse response ) {
|
||||
String version = new String( "<?xml version=\"1.0\" encoding=\"utf-8\"?><CloudS3Version>1.04</CloudS3Version>" );
|
||||
response.setStatus(200);
|
||||
endResponse(response, version);
|
||||
}
|
||||
|
||||
/**
|
||||
* This request registers the user Cloud.com account holder to the S3 service. The Cloud.com
|
||||
* account holder saves his API access and secret keys with the S3 service so that
|
||||
* each rest call he makes can be verified was originated from him. The given API access
|
||||
* and secret key are saved into the "usercredentials" database table.
|
||||
*
|
||||
* This is an unauthenticated REST call. The only required parameters are 'accesskey' and
|
||||
* 'secretkey'.
|
||||
*
|
||||
* To verify that the given keys represent an existing account they are used to execute the
|
||||
* Cloud.com's listAccounts API function. If the keys do not represent a valid account the
|
||||
* listAccounts function will fail.
|
||||
*
|
||||
* A user can call this REST function any number of times, on each call the Cloud.com secret
|
||||
* key is simply over writes any previously stored value.
|
||||
*
|
||||
* As with all REST calls HTTPS should be used to ensure their security.
|
||||
*/
|
||||
private void setUserKeys( HttpServletRequest request, HttpServletResponse response ) {
|
||||
String[] accessKey = null;
|
||||
String[] secretKey = null;
|
||||
|
||||
try {
|
||||
// -> both these parameters are required
|
||||
accessKey = request.getParameterValues( "accesskey" );
|
||||
if ( null == accessKey || 0 == accessKey.length ) {
|
||||
response.sendError(530, "Missing accesskey parameter" );
|
||||
return;
|
||||
}
|
||||
|
||||
secretKey = request.getParameterValues( "secretkey" );
|
||||
if ( null == secretKey || 0 == secretKey.length ) {
|
||||
response.sendError(530, "Missing secretkey parameter" );
|
||||
return;
|
||||
}
|
||||
} catch( Exception e ) {
|
||||
logger.error("SetUserKeys exception " + e.getMessage(), e);
|
||||
response.setStatus(500);
|
||||
endResponse(response, "SetUserKeys exception " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// -> use the keys to see if the account actually exists
|
||||
//ServiceProvider.getInstance().getEC2Engine().validateAccount( accessKey[0], secretKey[0] );
|
||||
UserCredentialsDao credentialDao = new UserCredentialsDao();
|
||||
credentialDao.setUserKeys( accessKey[0], secretKey[0] );
|
||||
|
||||
} catch( Exception e ) {
|
||||
logger.error("SetUserKeys " + e.getMessage(), e);
|
||||
response.setStatus(401);
|
||||
endResponse(response, e.toString());
|
||||
return;
|
||||
}
|
||||
response.setStatus(200);
|
||||
endResponse(response, "User keys set successfully");
|
||||
}
|
||||
|
||||
/**
|
||||
* We are using the S3AuthParams class to hide where the header values are coming
|
||||
* from so that the authenticateRequest call can be made from several places.
|
||||
*/
|
||||
public static S3AuthParams extractRequestHeaders( HttpServletRequest request ) {
|
||||
S3AuthParams params = new S3AuthParams();
|
||||
|
||||
Enumeration headers = request.getHeaderNames();
|
||||
if (null != headers)
|
||||
{
|
||||
while( headers.hasMoreElements())
|
||||
{
|
||||
HeaderParam oneHeader = new HeaderParam();
|
||||
String headerName = (String)headers.nextElement();
|
||||
oneHeader.setName( headerName );
|
||||
oneHeader.setValue( request.getHeader( headerName ));
|
||||
params.addHeader( oneHeader );
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
public static void authenticateRequest( HttpServletRequest request, S3AuthParams params )
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException
|
||||
{
|
||||
RestAuth auth = new RestAuth(ServiceProvider.getInstance().getUseSubDomain());
|
||||
String AWSAccessKey = null;
|
||||
String signature = null;
|
||||
String authorization = null;
|
||||
|
||||
// [A] Is it an annonymous request?
|
||||
if (null == (authorization = params.getHeader( "Authorization" ))) {
|
||||
UserContext.current().initContext();
|
||||
return;
|
||||
}
|
||||
|
||||
// [B] Is it an authenticated request?
|
||||
int offset = authorization.indexOf( "AWS" );
|
||||
if (-1 != offset) {
|
||||
String temp = authorization.substring( offset+3 ).trim();
|
||||
offset = temp.indexOf( ":" );
|
||||
AWSAccessKey = temp.substring( 0, offset );
|
||||
signature = temp.substring( offset+1 );
|
||||
}
|
||||
|
||||
// [C] Calculate the signature from the request's headers
|
||||
auth.setDateHeader( request.getHeader( "Date" ));
|
||||
auth.setContentTypeHeader( request.getHeader( "Content-Type" ));
|
||||
auth.setContentMD5Header( request.getHeader( "Content-MD5" ));
|
||||
auth.setHostHeader( request.getHeader( "Host" ));
|
||||
auth.setQueryString( request.getQueryString());
|
||||
auth.addUriPath( request.getRequestURI());
|
||||
|
||||
// -> are their any Amazon specific (i.e. 'x-amz-' ) headers?
|
||||
HeaderParam[] headers = params.getHeaders();
|
||||
for( int i=0; null != headers && i < headers.length; i++ )
|
||||
{
|
||||
String headerName = headers[i].getName();
|
||||
String ignoreCase = headerName.toLowerCase();
|
||||
if (ignoreCase.startsWith( "x-amz-" ))
|
||||
auth.addAmazonHeader( headerName + ":" + headers[i].getValue());
|
||||
}
|
||||
|
||||
UserInfo info = ServiceProvider.getInstance().getUserInfo(AWSAccessKey);
|
||||
if (info == null) throw new PermissionDeniedException("Unable to authenticate access key: " + AWSAccessKey);
|
||||
|
||||
try {
|
||||
if (auth.verifySignature( request.getMethod(), info.getSecretKey(), signature )) {
|
||||
UserContext.current().initContext(AWSAccessKey, info.getSecretKey(), AWSAccessKey, info.getDescription(), request);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
} catch (SignatureException e) {
|
||||
throw new PermissionDeniedException(e);
|
||||
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new PermissionDeniedException(e);
|
||||
}
|
||||
throw new PermissionDeniedException("Invalid signature");
|
||||
}
|
||||
|
||||
|
||||
|
||||
private ServletAction routeRequest(HttpServletRequest request)
|
||||
{
|
||||
// URL routing for S3 REST calls.
|
||||
String pathInfo = request.getPathInfo();
|
||||
String bucketName = null;
|
||||
String key = null;
|
||||
|
||||
String serviceEndpoint = ServiceProvider.getInstance().getServiceEndpoint();
|
||||
String host = request.getHeader("Host");
|
||||
|
||||
// Check for unrecognized forms of URI information in request
|
||||
|
||||
if ( ( pathInfo == null ) || ( pathInfo.indexOf('/') != 0 ) )
|
||||
if ( "POST".equalsIgnoreCase(request.getMethod()) )
|
||||
// Case where request is POST operation with no pathinfo
|
||||
// This is the POST alternative to PUT described at s3.amazonaws.com API doc page 141
|
||||
{
|
||||
return routePlainPostRequest (request);
|
||||
}
|
||||
|
||||
|
||||
// Irrespective of whether the requester is using subdomain or full host naming of path expressions
|
||||
// to buckets, wherever the request is made up of a service endpoint followed by a /, in AWS S3 this always
|
||||
// conveys a ListAllMyBuckets command
|
||||
|
||||
if ( (serviceEndpoint.equalsIgnoreCase( host )) && (pathInfo.equalsIgnoreCase("/")) ) {
|
||||
request.setAttribute(S3Constants.BUCKET_ATTR_KEY, "/");
|
||||
return new S3BucketAction(); // for ListAllMyBuckets
|
||||
}
|
||||
|
||||
// Because there is a leading / at position 0 of pathInfo, now subtract this to process the remainder
|
||||
pathInfo = pathInfo.substring(1);
|
||||
|
||||
if (ServiceProvider.getInstance().getUseSubDomain())
|
||||
|
||||
{
|
||||
// -> verify the format of the bucket name
|
||||
int endPos = host.indexOf( ServiceProvider.getInstance().getMasterDomain());
|
||||
if ( endPos > 0 )
|
||||
{
|
||||
bucketName = host.substring(0, endPos);
|
||||
S3Engine.verifyBucketName( bucketName, false );
|
||||
request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName);
|
||||
}
|
||||
else request.setAttribute(S3Constants.BUCKET_ATTR_KEY, "");
|
||||
|
||||
if (pathInfo == null || pathInfo.equalsIgnoreCase("/"))
|
||||
{
|
||||
return new S3BucketAction();
|
||||
}
|
||||
else {
|
||||
String objectKey = pathInfo.substring(1);
|
||||
request.setAttribute(S3Constants.OBJECT_ATTR_KEY, objectKey);
|
||||
return new S3ObjectAction();
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
|
||||
{
|
||||
|
||||
int endPos = pathInfo.indexOf('/'); // Subsequent / character?
|
||||
|
||||
if (endPos < 1)
|
||||
{
|
||||
bucketName = pathInfo;
|
||||
S3Engine.verifyBucketName( bucketName, false );
|
||||
request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName);
|
||||
return new S3BucketAction();
|
||||
}
|
||||
else
|
||||
{
|
||||
bucketName = pathInfo.substring(0, endPos);
|
||||
key = pathInfo.substring(endPos + 1);
|
||||
S3Engine.verifyBucketName( bucketName, false );
|
||||
|
||||
if (!key.isEmpty())
|
||||
{
|
||||
request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName);
|
||||
request.setAttribute(S3Constants.OBJECT_ATTR_KEY, pathInfo.substring(endPos + 1));
|
||||
return new S3ObjectAction();
|
||||
}
|
||||
else {
|
||||
request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName);
|
||||
return new S3BucketAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void endResponse(HttpServletResponse response, String content) {
|
||||
try {
|
||||
byte[] data = content.getBytes();
|
||||
response.setContentLength(data.length);
|
||||
OutputStream os = response.getOutputStream();
|
||||
os.write(data);
|
||||
os.close();
|
||||
} catch(Throwable e) {
|
||||
logger.error("Unexpected exception " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeResponse(HttpServletResponse response, String content) throws IOException {
|
||||
byte[] data = content.getBytes();
|
||||
OutputStream os = response.getOutputStream();
|
||||
os.write(data);
|
||||
}
|
||||
|
||||
public static void writeResponse(HttpServletResponse response, InputStream is) throws IOException {
|
||||
byte[] data = new byte[4096];
|
||||
int length = 0;
|
||||
while((length = is.read(data)) > 0) {
|
||||
response.getOutputStream().write(data, 0, length);
|
||||
}
|
||||
}
|
||||
|
||||
// Route for the case where request is POST operation with no pathinfo
|
||||
// This is the POST alternative to PUT described at s3.amazonaws.com API doc, Amazon Simple
|
||||
// Storage Service API Reference API Version 2006-03-01 page 141.
|
||||
// The purpose of the plain POST operation is to add an object to a specified bucket using HTML forms.
|
||||
|
||||
private S3ObjectAction routePlainPostRequest (HttpServletRequest request)
|
||||
{
|
||||
// TODO - Remove the unnecessary fields below
|
||||
// Obtain the mandatory fields from the HTML form or otherwise fail with a logger message
|
||||
String keyString = request.getParameter("key");
|
||||
String metatagString = request.getParameter("x-amz-meta-tag");
|
||||
String bucketString = request.getParameter("Bucket");
|
||||
String aclString = request.getParameter("acl");
|
||||
String fileString = request.getParameter("file");
|
||||
|
||||
String accessKeyString = request.getParameter("AWSAccessKeyId");
|
||||
String signatureString = request.getParameter("Signature");
|
||||
|
||||
// Obtain the discretionary fields from the HTML form
|
||||
String policyKeyString = request.getParameter("Policy");
|
||||
String metauuidString = request.getParameter("x-amz-meta-uuid");
|
||||
String redirectString = request.getParameter("redirect");
|
||||
|
||||
// if none of the above are null then ...
|
||||
request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketString);
|
||||
request.setAttribute(S3Constants.OBJECT_ATTR_KEY, keyString);
|
||||
request.setAttribute(S3Constants.PLAIN_POST_ACCESS_KEY, accessKeyString);
|
||||
request.setAttribute(S3Constants.PLAIN_POST_SIGNATURE, signatureString);
|
||||
|
||||
// -> authenticated calls
|
||||
try {
|
||||
// S3AuthParams params = extractRequestHeaders( request );
|
||||
S3AuthParams params = new S3AuthParams();
|
||||
HeaderParam headerParam1 = new HeaderParam("accessKey", accessKeyString);
|
||||
params.addHeader(headerParam1);
|
||||
HeaderParam headerParam2 = new HeaderParam("secretKey", signatureString);
|
||||
params.addHeader(headerParam2);
|
||||
authenticateRequest( request, params );
|
||||
}
|
||||
catch (Exception e)
|
||||
{ logger.warn("Authentication details insufficient"); }
|
||||
|
||||
return new S3ObjectAction();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A DIME request is really a SOAP request that we are dealing with, and so its
|
||||
* authentication is the SOAP authentication approach. Since Axis2 does not handle
|
||||
* DIME messages we deal with them here.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
*/
|
||||
private void processDimeRequest(HttpServletRequest request, HttpServletResponse response) {
|
||||
S3PutObjectRequest putRequest = null;
|
||||
S3PutObjectResponse putResponse = null;
|
||||
int bytesRead = 0;
|
||||
|
||||
S3Engine engine = new S3Engine();
|
||||
|
||||
try {
|
||||
logRequest(request);
|
||||
|
||||
MultiPartDimeInputStream ds = new MultiPartDimeInputStream( request.getInputStream());
|
||||
|
||||
// -> the first stream MUST be the SOAP party
|
||||
if (ds.nextInputStream())
|
||||
{
|
||||
//logger.debug( "DIME msg [" + ds.getStreamType() + "," + ds.getStreamTypeFormat() + "," + ds.getStreamId() + "]" );
|
||||
byte[] buffer = new byte[8192];
|
||||
bytesRead = ds.read( buffer, 0, 8192 );
|
||||
//logger.debug( "DIME SOAP Bytes read: " + bytesRead );
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream( buffer, 0, bytesRead );
|
||||
putRequest = toEnginePutObjectRequest( bis );
|
||||
}
|
||||
|
||||
// -> we only need to support a DIME message with two bodyparts
|
||||
if (null != putRequest && ds.nextInputStream())
|
||||
{
|
||||
InputStream is = ds.getInputStream();
|
||||
putRequest.setData( is );
|
||||
}
|
||||
|
||||
// -> need to do SOAP level auth here, on failure return the SOAP fault
|
||||
StringBuffer xml = new StringBuffer();
|
||||
String AWSAccessKey = putRequest.getAccessKey();
|
||||
UserInfo info = ServiceProvider.getInstance().getUserInfo(AWSAccessKey);
|
||||
try
|
||||
{ S3SoapAuth.verifySignature( putRequest.getSignature(), "PutObject", putRequest.getRawTimestamp(), AWSAccessKey, info.getSecretKey());
|
||||
|
||||
} catch( AxisFault e ) {
|
||||
String reason = e.toString();
|
||||
int start = reason.indexOf( ".AxisFault:" );
|
||||
if (-1 != start) reason = reason.substring( start+11 );
|
||||
|
||||
xml.append( "<?xml version=\"1.0\" encoding=\"utf-8\"?>" );
|
||||
xml.append( "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" >\n" );
|
||||
xml.append( "<soap:Body>\n" );
|
||||
xml.append( "<soap:Fault>\n" );
|
||||
xml.append( "<faultcode>" ).append( e.getFaultCode().toString()).append( "</faultcode>\n" );
|
||||
xml.append( "<faultstring>" ).append( reason ).append( "</faultstring>\n" );
|
||||
xml.append( "</soap:Fault>\n" );
|
||||
xml.append( "</soap:Body></soap:Envelope>" );
|
||||
|
||||
endResponse(response, xml.toString());
|
||||
PersistContext.commitTransaction();
|
||||
return;
|
||||
}
|
||||
|
||||
// -> PutObject S3 Bucket Policy would be done in the engine.handleRequest() call
|
||||
UserContext.current().initContext( AWSAccessKey, info.getSecretKey(), AWSAccessKey, "S3 DIME request", request );
|
||||
putResponse = engine.handleRequest( putRequest );
|
||||
|
||||
xml.append( "<?xml version=\"1.0\" encoding=\"utf-8\"?>" );
|
||||
xml.append( "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:tns=\"http://s3.amazonaws.com/doc/2006-03-01/\">" );
|
||||
xml.append( "<soap:Body>" );
|
||||
xml.append( "<tns:PutObjectResponse>" );
|
||||
xml.append( "<tns:PutObjectResponse>" );
|
||||
xml.append( "<tns:ETag>\"").append( putResponse.getETag()).append( "\"</tns:ETag>" );
|
||||
xml.append( "<tns:LastModified>").append( DatatypeConverter.printDateTime(putResponse.getLastModified())).append( "</tns:LastModified>" );
|
||||
xml.append( "</tns:PutObjectResponse></tns:PutObjectResponse>" );
|
||||
xml.append( "</soap:Body></soap:Envelope>" );
|
||||
|
||||
endResponse(response, xml.toString());
|
||||
PersistContext.commitTransaction();
|
||||
}
|
||||
catch(PermissionDeniedException e) {
|
||||
logger.error("Unexpected exception " + e.getMessage(), e);
|
||||
response.setStatus(403);
|
||||
endResponse(response, "Access denied");
|
||||
}
|
||||
catch(Throwable e)
|
||||
{
|
||||
logger.error("Unexpected exception " + e.getMessage(), e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PersistContext.closeSession();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the SOAP XML we extract from the DIME message into our local object.
|
||||
* Here Axis2 is not parsing the SOAP for us. I tried to use the Amazon PutObject
|
||||
* parser but it keep throwing exceptions.
|
||||
*
|
||||
* @param putObjectInline
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static S3PutObjectRequest toEnginePutObjectRequest( InputStream is ) throws Exception
|
||||
{
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
dbf.setNamespaceAware( true );
|
||||
|
||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
Document doc = db.parse( is );
|
||||
Node parent = null;
|
||||
Node contents = null;
|
||||
NodeList children = null;
|
||||
String temp = null;
|
||||
String element = null;
|
||||
int count = 0;
|
||||
|
||||
S3PutObjectRequest request = new S3PutObjectRequest();
|
||||
|
||||
// [A] Pull out the simple nodes first
|
||||
NodeList part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Bucket" );
|
||||
if (null != part)
|
||||
{
|
||||
if (null != (contents = part.item( 0 )))
|
||||
request.setBucketName( contents.getFirstChild().getNodeValue());
|
||||
}
|
||||
part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Key" );
|
||||
if (null != part)
|
||||
{
|
||||
if (null != (contents = part.item( 0 )))
|
||||
request.setKey( contents.getFirstChild().getNodeValue());
|
||||
}
|
||||
part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "ContentLength" );
|
||||
if (null != part)
|
||||
{
|
||||
if (null != (contents = part.item( 0 )))
|
||||
{
|
||||
String length = contents.getFirstChild().getNodeValue();
|
||||
if (null != length) request.setContentLength( Long.decode( length ));
|
||||
}
|
||||
}
|
||||
part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "AWSAccessKeyId" );
|
||||
if (null != part)
|
||||
{
|
||||
if (null != (contents = part.item( 0 )))
|
||||
request.setAccessKey( contents.getFirstChild().getNodeValue());
|
||||
}
|
||||
part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Signature" );
|
||||
if (null != part)
|
||||
{
|
||||
if (null != (contents = part.item( 0 )))
|
||||
request.setSignature( contents.getFirstChild().getNodeValue());
|
||||
}
|
||||
part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Timestamp" );
|
||||
if (null != part)
|
||||
{
|
||||
if (null != (contents = part.item( 0 )))
|
||||
request.setRawTimestamp( contents.getFirstChild().getNodeValue());
|
||||
}
|
||||
part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "StorageClass" );
|
||||
if (null != part)
|
||||
{
|
||||
if (null != (contents = part.item( 0 )))
|
||||
request.setStorageClass( contents.getFirstChild().getNodeValue());
|
||||
}
|
||||
part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Credential" );
|
||||
if (null != part)
|
||||
{
|
||||
if (null != (contents = part.item( 0 )))
|
||||
request.setCredential( contents.getFirstChild().getNodeValue());
|
||||
}
|
||||
|
||||
|
||||
// [B] Get a list of all 'Metadata' elements
|
||||
part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Metadata" );
|
||||
if (null != part)
|
||||
{
|
||||
count = part.getLength();
|
||||
S3MetaDataEntry[] metaEntry = new S3MetaDataEntry[ count ];
|
||||
|
||||
for( int i=0; i < count; i++ )
|
||||
{
|
||||
parent = part.item(i);
|
||||
metaEntry[i] = new S3MetaDataEntry();
|
||||
|
||||
// -> get a list of all the children elements of the 'Metadata' parent element
|
||||
if (null != (children = parent.getChildNodes()))
|
||||
{
|
||||
int numChildren = children.getLength();
|
||||
for( int j=0; j < numChildren; j++ )
|
||||
{
|
||||
contents = children.item( j );
|
||||
element = contents.getNodeName().trim();
|
||||
if ( element.endsWith( "Name" ))
|
||||
{
|
||||
temp = contents.getFirstChild().getNodeValue();
|
||||
if (null != temp) metaEntry[i].setName( temp );
|
||||
}
|
||||
else if (element.endsWith( "Value" ))
|
||||
{
|
||||
temp = contents.getFirstChild().getNodeValue();
|
||||
if (null != temp) metaEntry[i].setValue( temp );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
request.setMetaEntries( metaEntry );
|
||||
}
|
||||
|
||||
// [C] Get a list of all Grant elements in an AccessControlList
|
||||
part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Grant" );
|
||||
if (null != part)
|
||||
{
|
||||
S3AccessControlList engineAcl = new S3AccessControlList();
|
||||
|
||||
count = part.getLength();
|
||||
for( int i=0; i < count; i++ )
|
||||
{
|
||||
parent = part.item(i);
|
||||
S3Grant engineGrant = new S3Grant();
|
||||
|
||||
// -> get a list of all the children elements of the 'Grant' parent element
|
||||
if (null != (children = parent.getChildNodes()))
|
||||
{
|
||||
int numChildren = children.getLength();
|
||||
for( int j=0; j < numChildren; j++ )
|
||||
{
|
||||
contents = children.item( j );
|
||||
element = contents.getNodeName().trim();
|
||||
if ( element.endsWith( "Grantee" ))
|
||||
{
|
||||
NamedNodeMap attbs = contents.getAttributes();
|
||||
if (null != attbs)
|
||||
{
|
||||
Node type = attbs.getNamedItemNS( "http://www.w3.org/2001/XMLSchema-instance", "type" );
|
||||
if ( null != type )
|
||||
temp = type.getFirstChild().getNodeValue().trim();
|
||||
else temp = null;
|
||||
|
||||
if ( null != temp && temp.equalsIgnoreCase( "CanonicalUser" ))
|
||||
{
|
||||
engineGrant.setGrantee(SAcl.GRANTEE_USER);
|
||||
engineGrant.setCanonicalUserID( getChildNodeValue( contents, "ID" ));
|
||||
}
|
||||
else throw new UnsupportedOperationException( "Missing http://www.w3.org/2001/XMLSchema-instance:type value" );
|
||||
}
|
||||
}
|
||||
else if (element.endsWith( "Permission" ))
|
||||
{
|
||||
temp = contents.getFirstChild().getNodeValue().trim();
|
||||
if (temp.equalsIgnoreCase("READ" )) engineGrant.setPermission(SAcl.PERMISSION_READ);
|
||||
else if (temp.equalsIgnoreCase("WRITE" )) engineGrant.setPermission(SAcl.PERMISSION_WRITE);
|
||||
else if (temp.equalsIgnoreCase("READ_ACP" )) engineGrant.setPermission(SAcl.PERMISSION_READ_ACL);
|
||||
else if (temp.equalsIgnoreCase("WRITE_ACP" )) engineGrant.setPermission(SAcl.PERMISSION_WRITE_ACL);
|
||||
else if (temp.equalsIgnoreCase("FULL_CONTROL")) engineGrant.setPermission(SAcl.PERMISSION_FULL);
|
||||
else throw new UnsupportedOperationException( "Unsupported permission: " + temp );
|
||||
}
|
||||
}
|
||||
engineAcl.addGrant( engineGrant );
|
||||
}
|
||||
}
|
||||
request.setAcl( engineAcl );
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Have to deal with XML with and without namespaces.
|
||||
*/
|
||||
public static NodeList getElement( Document doc, String namespace, String tagName )
|
||||
{
|
||||
NodeList part = doc.getElementsByTagNameNS( namespace, tagName );
|
||||
if (null == part || 0 == part.getLength()) part = doc.getElementsByTagName( tagName );
|
||||
|
||||
return part;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looking for the value of a specific child of the given parent node.
|
||||
*
|
||||
* @param parent
|
||||
* @param childName
|
||||
* @return
|
||||
*/
|
||||
private static String getChildNodeValue( Node parent, String childName )
|
||||
{
|
||||
NodeList children = null;
|
||||
Node element = null;
|
||||
|
||||
if (null != (children = parent.getChildNodes()))
|
||||
{
|
||||
int numChildren = children.getLength();
|
||||
for( int i=0; i < numChildren; i++ )
|
||||
{
|
||||
if (null != (element = children.item( i )))
|
||||
{
|
||||
// -> name may have a namespace on it
|
||||
String name = element.getNodeName().trim();
|
||||
if ( name.endsWith( childName ))
|
||||
{
|
||||
String value = element.getFirstChild().getNodeValue();
|
||||
if (null != value) value = value.trim();
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void logRequest(HttpServletRequest request) {
|
||||
if(logger.isInfoEnabled()) {
|
||||
logger.info("Request method: " + request.getMethod());
|
||||
logger.info("Request contextPath: " + request.getContextPath());
|
||||
logger.info("Request pathInfo: " + request.getPathInfo());
|
||||
logger.info("Request pathTranslated: " + request.getPathTranslated());
|
||||
logger.info("Request queryString: " + request.getQueryString());
|
||||
logger.info("Request requestURI: " + request.getRequestURI());
|
||||
logger.info("Request requestURL: " + request.getRequestURL());
|
||||
logger.info("Request servletPath: " + request.getServletPath());
|
||||
Enumeration headers = request.getHeaderNames();
|
||||
if(headers != null) {
|
||||
while(headers.hasMoreElements()) {
|
||||
Object headerName = headers.nextElement();
|
||||
logger.info("Request header " + headerName + ":" + request.getHeader((String)headerName));
|
||||
}
|
||||
}
|
||||
|
||||
Enumeration params = request.getParameterNames();
|
||||
if(params != null) {
|
||||
while(params.hasMoreElements()) {
|
||||
Object paramName = params.nextElement();
|
||||
logger.info("Request parameter " + paramName + ":" +
|
||||
request.getParameter((String)paramName));
|
||||
}
|
||||
}
|
||||
logger.info( "- End of request -" );
|
||||
}
|
||||
}
|
||||
}
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
|
|
|||
|
|
@ -33,7 +33,11 @@ public class UserContext {
|
|||
private boolean annonymous = false;
|
||||
private String accessKey;
|
||||
private String secretKey;
|
||||
<<<<<<< HEAD
|
||||
private String canonicalUserId; // -> for us this is the accessKey
|
||||
=======
|
||||
private String canonicalUserId; // In our design, we re-use the accessKey to provide the canonicalUserId -- TODO loPri - reconsider?
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
private String description;
|
||||
private HttpServletRequest request = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
/*
|
||||
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved.
|
||||
*
|
||||
|
|
@ -912,3 +913,950 @@ public class S3BucketAction implements ServletAction {
|
|||
else return null;
|
||||
}
|
||||
}
|
||||
=======
|
||||
/*
|
||||
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.cloud.bridge.service.controller.s3;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Calendar;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import com.amazon.s3.GetBucketAccessControlPolicyResponse;
|
||||
import com.amazon.s3.ListAllMyBucketsResponse;
|
||||
import com.amazon.s3.ListBucketResponse;
|
||||
import com.cloud.bridge.io.MTOMAwareResultStreamWriter;
|
||||
import com.cloud.bridge.model.SAcl;
|
||||
import com.cloud.bridge.model.SBucket;
|
||||
import com.cloud.bridge.model.SHost;
|
||||
import com.cloud.bridge.persist.PersistContext;
|
||||
import com.cloud.bridge.persist.dao.BucketPolicyDao;
|
||||
import com.cloud.bridge.persist.dao.MultipartLoadDao;
|
||||
import com.cloud.bridge.persist.dao.SAclDao;
|
||||
import com.cloud.bridge.persist.dao.SBucketDao;
|
||||
import com.cloud.bridge.service.S3Constants;
|
||||
import com.cloud.bridge.service.S3RestServlet;
|
||||
import com.cloud.bridge.service.UserContext;
|
||||
import com.cloud.bridge.service.core.s3.S3AccessControlList;
|
||||
import com.cloud.bridge.service.core.s3.S3AccessControlPolicy;
|
||||
import com.cloud.bridge.service.core.s3.S3BucketAdapter;
|
||||
import com.cloud.bridge.service.core.s3.S3BucketPolicy;
|
||||
import com.cloud.bridge.service.core.s3.S3CanonicalUser;
|
||||
import com.cloud.bridge.service.core.s3.S3CreateBucketConfiguration;
|
||||
import com.cloud.bridge.service.core.s3.S3CreateBucketRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3CreateBucketResponse;
|
||||
import com.cloud.bridge.service.core.s3.S3DeleteBucketRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3Engine;
|
||||
import com.cloud.bridge.service.core.s3.S3GetBucketAccessControlPolicyRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3Grant;
|
||||
import com.cloud.bridge.service.core.s3.S3ListAllMyBucketsRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3ListAllMyBucketsResponse;
|
||||
import com.cloud.bridge.service.core.s3.S3ListBucketObjectEntry;
|
||||
import com.cloud.bridge.service.core.s3.S3ListBucketRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3ListBucketResponse;
|
||||
import com.cloud.bridge.service.core.s3.S3MultipartUpload;
|
||||
import com.cloud.bridge.service.core.s3.S3PolicyContext;
|
||||
import com.cloud.bridge.service.core.s3.S3PutObjectRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3Response;
|
||||
import com.cloud.bridge.service.core.s3.S3SetBucketAccessControlPolicyRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3BucketPolicy.PolicyAccess;
|
||||
import com.cloud.bridge.service.core.s3.S3PolicyAction.PolicyActions;
|
||||
import com.cloud.bridge.service.core.s3.S3PolicyCondition.ConditionKeys;
|
||||
import com.cloud.bridge.service.exception.InternalErrorException;
|
||||
import com.cloud.bridge.service.exception.InvalidBucketName;
|
||||
import com.cloud.bridge.service.exception.InvalidRequestContentException;
|
||||
import com.cloud.bridge.service.exception.NetworkIOException;
|
||||
import com.cloud.bridge.service.exception.ObjectAlreadyExistsException;
|
||||
import com.cloud.bridge.service.exception.OutOfServiceException;
|
||||
import com.cloud.bridge.service.exception.PermissionDeniedException;
|
||||
import com.cloud.bridge.util.Converter;
|
||||
import com.cloud.bridge.util.DateHelper;
|
||||
import com.cloud.bridge.util.PolicyParser;
|
||||
import com.cloud.bridge.util.StringHelper;
|
||||
import com.cloud.bridge.util.OrderedPair;
|
||||
import com.cloud.bridge.util.Triple;
|
||||
import com.cloud.bridge.util.XSerializer;
|
||||
import com.cloud.bridge.util.XSerializerXmlAdapter;
|
||||
|
||||
|
||||
/**
|
||||
* @author Kelven Yang, John Zucker
|
||||
*/
|
||||
public class S3BucketAction implements ServletAction {
|
||||
protected final static Logger logger = Logger.getLogger(S3BucketAction.class);
|
||||
|
||||
private DocumentBuilderFactory dbf = null;
|
||||
public S3BucketAction() {
|
||||
dbf = DocumentBuilderFactory.newInstance();
|
||||
dbf.setNamespaceAware( true );
|
||||
|
||||
}
|
||||
|
||||
public void execute(HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, XMLStreamException
|
||||
{
|
||||
String method = request.getMethod();
|
||||
String queryString = request.getQueryString();
|
||||
|
||||
if ( method.equalsIgnoreCase("PUT"))
|
||||
{
|
||||
if ( queryString != null && queryString.length() > 0 )
|
||||
{
|
||||
if ( queryString.startsWith("acl")) {
|
||||
executePutBucketAcl(request, response);
|
||||
return;
|
||||
}
|
||||
else if (queryString.startsWith("versioning")) {
|
||||
executePutBucketVersioning(request, response);
|
||||
return;
|
||||
}
|
||||
else if (queryString.startsWith("policy")) {
|
||||
executePutBucketPolicy(request, response);
|
||||
return;
|
||||
}
|
||||
else if (queryString.startsWith("logging")) {
|
||||
executePutBucketLogging(request, response);
|
||||
return;
|
||||
}
|
||||
else if (queryString.startsWith("website")) {
|
||||
executePutBucketWebsite(request, response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
executePutBucket(request, response);
|
||||
}
|
||||
else if(method.equalsIgnoreCase("GET"))
|
||||
{
|
||||
if (queryString != null && queryString.length() > 0)
|
||||
{
|
||||
if ( queryString.startsWith("acl")) {
|
||||
executeGetBucketAcl(request, response);
|
||||
return;
|
||||
}
|
||||
else if (queryString.startsWith("versioning")) {
|
||||
executeGetBucketVersioning(request, response);
|
||||
return;
|
||||
}
|
||||
else if (queryString.contains("versions")) {
|
||||
executeGetBucketObjectVersions(request, response);
|
||||
return;
|
||||
}
|
||||
else if (queryString.startsWith("location")) {
|
||||
executeGetBucketLocation(request, response);
|
||||
return;
|
||||
}
|
||||
else if (queryString.startsWith("uploads")) {
|
||||
executeListMultipartUploads(request, response);
|
||||
return;
|
||||
}
|
||||
else if (queryString.startsWith("policy")) {
|
||||
executeGetBucketPolicy(request, response);
|
||||
return;
|
||||
}
|
||||
else if (queryString.startsWith("logging")) {
|
||||
executeGetBucketLogging(request, response);
|
||||
return;
|
||||
}
|
||||
else if (queryString.startsWith("website")) {
|
||||
executeGetBucketWebsite(request, response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String bucketAtr = (String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
|
||||
if ( bucketAtr.equals( "/" ))
|
||||
executeGetAllBuckets(request, response);
|
||||
else executeGetBucket(request, response);
|
||||
}
|
||||
else if (method.equalsIgnoreCase("DELETE"))
|
||||
{
|
||||
if (queryString != null && queryString.length() > 0)
|
||||
{
|
||||
if ( queryString.startsWith("policy")) {
|
||||
executeDeleteBucketPolicy(request, response);
|
||||
return;
|
||||
}
|
||||
else if (queryString.startsWith("website")) {
|
||||
executeDeleteBucketWebsite(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
executeDeleteBucket(request, response);
|
||||
}
|
||||
else if ( (method.equalsIgnoreCase("POST")) && (queryString.equalsIgnoreCase("delete")) )
|
||||
{
|
||||
// TODO - Hi Pri - Implement multi-object delete in a single command
|
||||
throw new InternalErrorException("Multi-object delete in a single command not yet implemented");
|
||||
}
|
||||
else throw new IllegalArgumentException("Unsupported method in REST request");
|
||||
}
|
||||
|
||||
/**
|
||||
* In order to support a policy on the "s3:CreateBucket" action we must be able to set and get
|
||||
* policies before a bucket is actually created.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @throws IOException
|
||||
*/
|
||||
private void executePutBucketPolicy(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
String bucketName = (String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
|
||||
String policy = streamToString( request.getInputStream());
|
||||
|
||||
// [A] Is there an owner of an existing policy or bucket?
|
||||
BucketPolicyDao policyDao = new BucketPolicyDao();
|
||||
SBucketDao bucketDao = new SBucketDao();
|
||||
SBucket bucket = bucketDao.getByName( bucketName );
|
||||
String owner = null;
|
||||
|
||||
if ( null != bucket )
|
||||
{
|
||||
owner = bucket.getOwnerCanonicalId();
|
||||
}
|
||||
else
|
||||
{ try {
|
||||
owner = policyDao.getPolicyOwner( bucketName );
|
||||
}
|
||||
catch( Exception e ) {}
|
||||
}
|
||||
|
||||
|
||||
// [B] "The bucket owner by default has permissions to attach bucket policies to their buckets using PUT Bucket policy."
|
||||
// -> the bucket owner may want to restrict the IP address from where this can be executed
|
||||
String client = UserContext.current().getCanonicalUserId();
|
||||
S3PolicyContext context = new S3PolicyContext( PolicyActions.PutBucketPolicy, bucketName );
|
||||
switch( S3Engine.verifyPolicy( context )) {
|
||||
case ALLOW:
|
||||
break;
|
||||
|
||||
case DEFAULT_DENY:
|
||||
if (null != owner && !client.equals( owner )) {
|
||||
response.setStatus(405);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case DENY:
|
||||
response.setStatus(403);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// [B] Place the policy into the database over writting an existing policy
|
||||
try {
|
||||
// -> first make sure that the policy is valid by parsing it
|
||||
PolicyParser parser = new PolicyParser();
|
||||
S3BucketPolicy sbp = parser.parse( policy, bucketName );
|
||||
|
||||
policyDao.deletePolicy( bucketName );
|
||||
if (null != policy && !policy.isEmpty()) policyDao.addPolicy( bucketName, client, policy );
|
||||
|
||||
if (null != sbp) ServiceProvider.getInstance().setBucketPolicy( bucketName, sbp );
|
||||
response.setStatus(200);
|
||||
}
|
||||
catch( PermissionDeniedException e ) {
|
||||
logger.error("Put Bucket Policy failed due to " + e.getMessage(), e);
|
||||
throw e;
|
||||
}
|
||||
catch( ParseException e ) {
|
||||
logger.error("Put Bucket Policy failed due to " + e.getMessage(), e);
|
||||
throw new PermissionDeniedException( e.toString());
|
||||
}
|
||||
catch( Exception e ) {
|
||||
logger.error("Put Bucket Policy failed due to " + e.getMessage(), e);
|
||||
response.setStatus(500);
|
||||
}
|
||||
}
|
||||
|
||||
private void executeGetBucketPolicy(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
String bucketName = (String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
|
||||
|
||||
// [A] Is there an owner of an existing policy or bucket?
|
||||
BucketPolicyDao policyDao = new BucketPolicyDao();
|
||||
SBucketDao bucketDao = new SBucketDao();
|
||||
SBucket bucket = bucketDao.getByName( bucketName );
|
||||
String owner = null;
|
||||
|
||||
if ( null != bucket )
|
||||
{
|
||||
owner = bucket.getOwnerCanonicalId();
|
||||
}
|
||||
else
|
||||
{ try {
|
||||
owner = policyDao.getPolicyOwner( bucketName );
|
||||
}
|
||||
catch( Exception e ) {}
|
||||
}
|
||||
|
||||
|
||||
// [B] "The bucket owner by default has permissions to retrieve bucket policies using GET Bucket policy."
|
||||
// -> the bucket owner may want to restrict the IP address from where this can be executed
|
||||
String client = UserContext.current().getCanonicalUserId();
|
||||
S3PolicyContext context = new S3PolicyContext( PolicyActions.GetBucketPolicy, bucketName );
|
||||
switch( S3Engine.verifyPolicy( context )) {
|
||||
case ALLOW:
|
||||
break;
|
||||
|
||||
case DEFAULT_DENY:
|
||||
if (null != owner && !client.equals( owner )) {
|
||||
response.setStatus(405);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case DENY:
|
||||
response.setStatus(403);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// [B] Pull the policy from the database if one exists
|
||||
try {
|
||||
String policy = policyDao.getPolicy( bucketName );
|
||||
if ( null == policy ) {
|
||||
response.setStatus(404);
|
||||
}
|
||||
else {
|
||||
response.setStatus(200);
|
||||
response.setContentType("application/json");
|
||||
S3RestServlet.endResponse(response, policy);
|
||||
}
|
||||
}
|
||||
catch( Exception e ) {
|
||||
logger.error("Get Bucket Policy failed due to " + e.getMessage(), e);
|
||||
response.setStatus(500);
|
||||
}
|
||||
}
|
||||
|
||||
private void executeDeleteBucketPolicy(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
String bucketName = (String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
|
||||
|
||||
SBucketDao bucketDao = new SBucketDao();
|
||||
SBucket bucket = bucketDao.getByName( bucketName );
|
||||
if (bucket != null)
|
||||
{
|
||||
String client = UserContext.current().getCanonicalUserId();
|
||||
if (!client.equals( bucket.getOwnerCanonicalId())) {
|
||||
response.setStatus(405);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
BucketPolicyDao policyDao = new BucketPolicyDao();
|
||||
String policy = policyDao.getPolicy( bucketName );
|
||||
if ( null == policy ) {
|
||||
response.setStatus(204);
|
||||
}
|
||||
else {
|
||||
ServiceProvider.getInstance().deleteBucketPolicy( bucketName );
|
||||
policyDao.deletePolicy( bucketName );
|
||||
response.setStatus(200);
|
||||
}
|
||||
}
|
||||
catch( Exception e ) {
|
||||
logger.error("Delete Bucket Policy failed due to " + e.getMessage(), e);
|
||||
response.setStatus(500);
|
||||
}
|
||||
}
|
||||
|
||||
public void executeGetAllBuckets(HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, XMLStreamException
|
||||
{
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set( 1970, 1, 1 );
|
||||
S3ListAllMyBucketsRequest engineRequest = new S3ListAllMyBucketsRequest();
|
||||
engineRequest.setAccessKey(UserContext.current().getAccessKey());
|
||||
engineRequest.setRequestTimestamp( cal );
|
||||
engineRequest.setSignature( "" );
|
||||
|
||||
|
||||
|
||||
|
||||
S3ListAllMyBucketsResponse engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest(engineRequest);
|
||||
|
||||
// To allow the all buckets list to be serialized via Axiom classes
|
||||
ListAllMyBucketsResponse allBuckets = S3SerializableServiceImplementation.toListAllMyBucketsResponse( engineResponse );
|
||||
|
||||
OutputStream outputStream = response.getOutputStream();
|
||||
response.setStatus(200);
|
||||
response.setContentType("application/xml");
|
||||
// The content-type literally should be "application/xml; charset=UTF-8"
|
||||
// but any compliant JVM supplies utf-8 by default
|
||||
|
||||
MTOMAwareResultStreamWriter resultWriter = new MTOMAwareResultStreamWriter ("ListAllMyBucketsResult", outputStream );
|
||||
resultWriter.startWrite();
|
||||
resultWriter.writeout(allBuckets);
|
||||
resultWriter.stopWrite();
|
||||
|
||||
}
|
||||
|
||||
public void executeGetBucket(HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, XMLStreamException
|
||||
{
|
||||
S3ListBucketRequest engineRequest = new S3ListBucketRequest();
|
||||
engineRequest.setBucketName((String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY));
|
||||
engineRequest.setDelimiter(request.getParameter("delimiter"));
|
||||
engineRequest.setMarker(request.getParameter("marker"));
|
||||
engineRequest.setPrefix(request.getParameter("prefix"));
|
||||
|
||||
int maxKeys = Converter.toInt(request.getParameter("max-keys"), 1000);
|
||||
engineRequest.setMaxKeys(maxKeys);
|
||||
S3ListBucketResponse engineResponse = ServiceProvider.getInstance().getS3Engine().listBucketContents( engineRequest, false );
|
||||
|
||||
// To allow the all list buckets result to be serialized via Axiom classes
|
||||
ListBucketResponse oneBucket = S3SerializableServiceImplementation.toListBucketResponse( engineResponse );
|
||||
|
||||
OutputStream outputStream = response.getOutputStream();
|
||||
response.setStatus(200);
|
||||
response.setContentType("application/xml");
|
||||
// The content-type literally should be "application/xml; charset=UTF-8"
|
||||
// but any compliant JVM supplies utf-8 by default;
|
||||
|
||||
MTOMAwareResultStreamWriter resultWriter = new MTOMAwareResultStreamWriter ("ListBucketResult", outputStream );
|
||||
resultWriter.startWrite();
|
||||
resultWriter.writeout(oneBucket);
|
||||
resultWriter.stopWrite();
|
||||
|
||||
}
|
||||
|
||||
public void executeGetBucketAcl(HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, XMLStreamException
|
||||
{
|
||||
S3GetBucketAccessControlPolicyRequest engineRequest = new S3GetBucketAccessControlPolicyRequest();
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set( 1970, 1, 1 );
|
||||
engineRequest.setAccessKey(UserContext.current().getAccessKey());
|
||||
engineRequest.setRequestTimestamp( cal );
|
||||
engineRequest.setSignature( "" ); // TODO - Consider providing signature in a future release which allows additional user description
|
||||
engineRequest.setBucketName((String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY));
|
||||
|
||||
S3AccessControlPolicy engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest(engineRequest);
|
||||
|
||||
// To allow the bucket acl policy result to be serialized via Axiom classes
|
||||
GetBucketAccessControlPolicyResponse onePolicy = S3SerializableServiceImplementation.toGetBucketAccessControlPolicyResponse( engineResponse );
|
||||
|
||||
OutputStream outputStream = response.getOutputStream();
|
||||
response.setStatus(200);
|
||||
response.setContentType("application/xml");
|
||||
// The content-type literally should be "application/xml; charset=UTF-8"
|
||||
// but any compliant JVM supplies utf-8 by default;
|
||||
|
||||
MTOMAwareResultStreamWriter resultWriter = new MTOMAwareResultStreamWriter ("GetBucketAccessControlPolicyResult", outputStream );
|
||||
resultWriter.startWrite();
|
||||
resultWriter.writeout(onePolicy);
|
||||
resultWriter.stopWrite();
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void executeGetBucketVersioning(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
// [A] Does the bucket exist?
|
||||
String bucketName = (String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
|
||||
String versioningStatus = null;
|
||||
|
||||
if (null == bucketName) {
|
||||
logger.error( "executeGetBucketVersioning - no bucket name given" );
|
||||
response.setStatus( 400 );
|
||||
return;
|
||||
}
|
||||
|
||||
SBucketDao bucketDao = new SBucketDao();
|
||||
SBucket sbucket = bucketDao.getByName( bucketName );
|
||||
if (sbucket == null) {
|
||||
response.setStatus( 404 );
|
||||
return;
|
||||
}
|
||||
|
||||
// [B] The owner may want to restrict the IP address at which this can be performed
|
||||
String client = UserContext.current().getCanonicalUserId();
|
||||
if (!client.equals( sbucket.getOwnerCanonicalId()))
|
||||
throw new PermissionDeniedException( "Access Denied - only the owner can read bucket versioning" );
|
||||
|
||||
S3PolicyContext context = new S3PolicyContext( PolicyActions.GetBucketVersioning, bucketName );
|
||||
if (PolicyAccess.DENY == S3Engine.verifyPolicy( context )) {
|
||||
response.setStatus(403);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// [C]
|
||||
switch( sbucket.getVersioningStatus()) {
|
||||
default:
|
||||
case 0: versioningStatus = ""; break;
|
||||
case 1: versioningStatus = "Enabled"; break;
|
||||
case 2: versioningStatus = "Suspended"; break;
|
||||
}
|
||||
|
||||
StringBuffer xml = new StringBuffer();
|
||||
xml.append( "<?xml version=\"1.0\" encoding=\"utf-8\"?>" );
|
||||
xml.append( "<VersioningConfiguration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">" );
|
||||
if (0 < versioningStatus.length()) xml.append( "<Status>" ).append( versioningStatus ).append( "</Status>" );
|
||||
xml.append( "</VersioningConfiguration>" );
|
||||
|
||||
response.setStatus(200);
|
||||
response.setContentType("text/xml; charset=UTF-8");
|
||||
S3RestServlet.endResponse(response, xml.toString());
|
||||
}
|
||||
|
||||
public void executeGetBucketObjectVersions(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
S3ListBucketRequest engineRequest = new S3ListBucketRequest();
|
||||
String keyMarker = request.getParameter("key-marker");
|
||||
String versionIdMarker = request.getParameter("version-id-marker");
|
||||
|
||||
engineRequest.setBucketName((String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY));
|
||||
engineRequest.setDelimiter(request.getParameter("delimiter"));
|
||||
engineRequest.setMarker( keyMarker );
|
||||
engineRequest.setPrefix(request.getParameter("prefix"));
|
||||
engineRequest.setVersionIdMarker( versionIdMarker );
|
||||
|
||||
int maxKeys = Converter.toInt(request.getParameter("max-keys"), 1000);
|
||||
engineRequest.setMaxKeys(maxKeys);
|
||||
S3ListBucketResponse engineResponse = ServiceProvider.getInstance().getS3Engine().listBucketContents( engineRequest, true );
|
||||
|
||||
// -> the SOAP version produces different XML
|
||||
StringBuffer xml = new StringBuffer();
|
||||
xml.append( "<?xml version=\"1.0\" encoding=\"utf-8\"?>" );
|
||||
xml.append( "<ListVersionsResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">" );
|
||||
xml.append( "<Name>" ).append( engineResponse.getBucketName()).append( "</Name>" );
|
||||
|
||||
if ( null == keyMarker )
|
||||
xml.append( "<KeyMarker/>" );
|
||||
else xml.append( "<KeyMarker>" ).append( keyMarker ).append( "</KeyMarker" );
|
||||
|
||||
if ( null == versionIdMarker )
|
||||
xml.append( "<VersionIdMarker/>" );
|
||||
else xml.append( "<VersionIdMarker>" ).append( keyMarker ).append( "</VersionIdMarker" );
|
||||
|
||||
xml.append( "<MaxKeys>" ).append( engineResponse.getMaxKeys()).append( "</MaxKeys>" );
|
||||
xml.append( "<IsTruncated>" ).append( engineResponse.isTruncated()).append( "</IsTruncated>" );
|
||||
|
||||
S3ListBucketObjectEntry[] versions = engineResponse.getContents();
|
||||
for( int i=0; null != versions && i < versions.length; i++ )
|
||||
{
|
||||
S3CanonicalUser owner = versions[i].getOwner();
|
||||
boolean isDeletionMarker = versions[i].getIsDeletionMarker();
|
||||
String displayName = owner.getDisplayName();
|
||||
String id = owner.getID();
|
||||
|
||||
if ( isDeletionMarker )
|
||||
{
|
||||
xml.append( "<DeleteMarker>" );
|
||||
xml.append( "<Key>" ).append( versions[i].getKey()).append( "</Key>" );
|
||||
xml.append( "<VersionId>" ).append( versions[i].getVersion()).append( "</VersionId>" );
|
||||
xml.append( "<IsLatest>" ).append( versions[i].getIsLatest()).append( "</IsLatest>" );
|
||||
xml.append( "<LastModified>" ).append( DatatypeConverter.printDateTime( versions[i].getLastModified())).append( "</LastModified>" );
|
||||
}
|
||||
else
|
||||
{ xml.append( "<Version>" );
|
||||
xml.append( "<Key>" ).append( versions[i].getKey()).append( "</Key>" );
|
||||
xml.append( "<VersionId>" ).append( versions[i].getVersion()).append( "</VersionId>" );
|
||||
xml.append( "<IsLatest>" ).append( versions[i].getIsLatest()).append( "</IsLatest>" );
|
||||
xml.append( "<LastModified>" ).append( DatatypeConverter.printDateTime( versions[i].getLastModified())).append( "</LastModified>" );
|
||||
xml.append( "<ETag>" ).append( versions[i].getETag()).append( "</ETag>" );
|
||||
xml.append( "<Size>" ).append( versions[i].getSize()).append( "</Size>" );
|
||||
xml.append( "<StorageClass>" ).append( versions[i].getStorageClass()).append( "</StorageClass>" );
|
||||
}
|
||||
|
||||
xml.append( "<Owner>" );
|
||||
xml.append( "<ID>" ).append( id ).append( "</ID>" );
|
||||
if ( null == displayName )
|
||||
xml.append( "<DisplayName/>" );
|
||||
else xml.append( "<DisplayName>" ).append( owner.getDisplayName()).append( "</DisplayName>" );
|
||||
xml.append( "</Owner>" );
|
||||
|
||||
if ( isDeletionMarker )
|
||||
xml.append( "</DeleteMarker>" );
|
||||
else xml.append( "</Version>" );
|
||||
}
|
||||
xml.append( "</ListVersionsResult>" );
|
||||
|
||||
response.setStatus(200);
|
||||
response.setContentType("text/xml; charset=UTF-8");
|
||||
S3RestServlet.endResponse(response, xml.toString());
|
||||
}
|
||||
|
||||
public void executeGetBucketLogging(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
// TODO -- Review this in future. Currently this is a beta feature of S3
|
||||
response.setStatus(405);
|
||||
}
|
||||
|
||||
public void executeGetBucketLocation(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
response.setStatus(405);
|
||||
}
|
||||
|
||||
public void executeGetBucketWebsite(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
response.setStatus(405);
|
||||
}
|
||||
|
||||
public void executeDeleteBucketWebsite(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
response.setStatus(405);
|
||||
}
|
||||
|
||||
public void executePutBucket(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
int contentLength = request.getContentLength();
|
||||
Object objectInContent = null;
|
||||
|
||||
if(contentLength > 0)
|
||||
{
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = request.getInputStream();
|
||||
String xml = StringHelper.stringFromStream(is);
|
||||
XSerializer serializer = new XSerializer(new XSerializerXmlAdapter());
|
||||
objectInContent = serializer.serializeFrom(xml);
|
||||
if(objectInContent != null && !(objectInContent instanceof S3CreateBucketConfiguration)) {
|
||||
throw new InvalidRequestContentException("Invalid request content in create-bucket: " + xml);
|
||||
}
|
||||
is.close();
|
||||
|
||||
} catch (IOException e) {
|
||||
logger.error("Unable to read request data due to " + e.getMessage(), e);
|
||||
throw new NetworkIOException(e);
|
||||
|
||||
} finally {
|
||||
if(is != null) is.close();
|
||||
}
|
||||
}
|
||||
|
||||
S3CreateBucketRequest engineRequest = new S3CreateBucketRequest();
|
||||
engineRequest.setBucketName((String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY));
|
||||
engineRequest.setConfig((S3CreateBucketConfiguration)objectInContent);
|
||||
|
||||
S3CreateBucketResponse engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest(engineRequest);
|
||||
response.addHeader("Location", "/" + engineResponse.getBucketName());
|
||||
response.setContentLength(0);
|
||||
response.setStatus(200);
|
||||
response.flushBuffer();
|
||||
}
|
||||
|
||||
public void executePutBucketAcl(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
// [A] Determine that there is an applicable bucket which might have an ACL set
|
||||
|
||||
String bucketName = (String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
|
||||
SBucketDao bucketDao = new SBucketDao();
|
||||
SBucket bucket = bucketDao.getByName( bucketName );
|
||||
String owner = null;
|
||||
if ( null != bucket )
|
||||
owner = bucket.getOwnerCanonicalId();
|
||||
if (null == owner)
|
||||
{
|
||||
logger.error( "ACL update failed since " + bucketName + " does not exist" );
|
||||
throw new IOException("ACL update failed");
|
||||
}
|
||||
|
||||
// [B] Obtain the grant request which applies to the acl request string. This latter is supplied as the value of the x-amz-acl header.
|
||||
|
||||
S3SetBucketAccessControlPolicyRequest engineRequest = new S3SetBucketAccessControlPolicyRequest();
|
||||
S3Grant grantRequest = new S3Grant();
|
||||
S3AccessControlList aclRequest = new S3AccessControlList();
|
||||
|
||||
String aclRequestString = request.getHeader("x-amz-acl");
|
||||
OrderedPair <Integer,Integer> accessControlsForBucketOwner = SAcl.getCannedAccessControls(aclRequestString,"SBucket");
|
||||
grantRequest.setPermission(accessControlsForBucketOwner.getFirst());
|
||||
grantRequest.setGrantee(accessControlsForBucketOwner.getSecond());
|
||||
grantRequest.setCanonicalUserID(owner);
|
||||
aclRequest.addGrant(grantRequest);
|
||||
engineRequest.setAcl(aclRequest);
|
||||
engineRequest.setBucketName(bucketName);
|
||||
|
||||
|
||||
// [C] Allow an S3Engine to handle the S3SetBucketAccessControlPolicyRequest
|
||||
S3Response engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest(engineRequest);
|
||||
response.setStatus( engineResponse.getResultCode());
|
||||
|
||||
}
|
||||
|
||||
public void executePutBucketVersioning(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
String bucketName = (String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
|
||||
String versioningStatus = null;
|
||||
Node item = null;
|
||||
|
||||
if (null == bucketName) {
|
||||
logger.error( "executePutBucketVersioning - no bucket name given" );
|
||||
response.setStatus( 400 );
|
||||
return;
|
||||
}
|
||||
|
||||
// -> is the XML as defined?
|
||||
try {
|
||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
Document restXML = db.parse( request.getInputStream());
|
||||
NodeList match = S3RestServlet.getElement( restXML, "http://s3.amazonaws.com/doc/2006-03-01/", "Status" );
|
||||
if ( 0 < match.getLength())
|
||||
{
|
||||
item = match.item(0);
|
||||
versioningStatus = new String( item.getFirstChild().getNodeValue());
|
||||
}
|
||||
else
|
||||
{ logger.error( "executePutBucketVersioning - cannot find Status tag in XML body" );
|
||||
response.setStatus( 400 );
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch( Exception e ) {
|
||||
logger.error( "executePutBucketVersioning - failed to parse XML due to " + e.getMessage(), e);
|
||||
response.setStatus(400);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Irrespective of what the ACLs say only the owner can turn on versioning on a bucket.
|
||||
// The bucket owner may want to restrict the IP address from which this can occur.
|
||||
SBucketDao bucketDao = new SBucketDao();
|
||||
SBucket sbucket = bucketDao.getByName( bucketName );
|
||||
|
||||
String client = UserContext.current().getCanonicalUserId();
|
||||
if (!client.equals( sbucket.getOwnerCanonicalId()))
|
||||
throw new PermissionDeniedException( "Access Denied - only the owner can turn on versioing on a bucket" );
|
||||
|
||||
S3PolicyContext context = new S3PolicyContext( PolicyActions.PutBucketVersioning, bucketName );
|
||||
if (PolicyAccess.DENY == S3Engine.verifyPolicy( context )) {
|
||||
response.setStatus(403);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (versioningStatus.equalsIgnoreCase( "Enabled" )) sbucket.setVersioningStatus( 1 );
|
||||
else if (versioningStatus.equalsIgnoreCase( "Suspended")) sbucket.setVersioningStatus( 2 );
|
||||
else {
|
||||
logger.error( "executePutBucketVersioning - unknown state: [" + versioningStatus + "]" );
|
||||
response.setStatus( 400 );
|
||||
return;
|
||||
}
|
||||
bucketDao.update( sbucket );
|
||||
|
||||
} catch( PermissionDeniedException e ) {
|
||||
logger.error( "executePutBucketVersioning - failed due to " + e.getMessage(), e);
|
||||
throw e;
|
||||
|
||||
} catch( Exception e ) {
|
||||
logger.error( "executePutBucketVersioning - failed due to " + e.getMessage(), e);
|
||||
response.setStatus(500);
|
||||
return;
|
||||
}
|
||||
response.setStatus(200);
|
||||
}
|
||||
|
||||
public void executePutBucketLogging(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
// TODO -- Review this in future. Currently this is a S3 beta feature
|
||||
response.setStatus(501);
|
||||
}
|
||||
|
||||
public void executePutBucketWebsite(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
// TODO -- LoPri - Undertake checks on Put Bucket Website
|
||||
// Tested using configuration <Directory /Users/john1/S3-Mount>\nAllowOverride FileInfo AuthConfig Limit...</Directory> in httpd.conf
|
||||
// Need some way of using AllowOverride to allow use of .htaccess and then pushing .httaccess file to bucket subdirectory of mount point
|
||||
// Currently has noop effect in the sense that a running apachectl process sees the directory contents without further action
|
||||
response.setStatus(200);
|
||||
}
|
||||
|
||||
public void executeDeleteBucket(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
S3DeleteBucketRequest engineRequest = new S3DeleteBucketRequest();
|
||||
engineRequest.setBucketName((String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY));
|
||||
S3Response engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest(engineRequest);
|
||||
response.setStatus(engineResponse.getResultCode());
|
||||
response.flushBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Multipart upload is a complex operation with all the options defined by Amazon. Part of the functionality is
|
||||
* provided by the query done against the database. The CommonPrefixes functionality is done the same way
|
||||
* as done in the listBucketContents function (i.e., by iterating though the list to decide which output
|
||||
* element each key is placed).
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @throws IOException
|
||||
*/
|
||||
public void executeListMultipartUploads(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
// [A] Obtain parameters and do basic bucket verification
|
||||
String bucketName = (String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
|
||||
String delimiter = request.getParameter("delimiter");
|
||||
String keyMarker = request.getParameter("key-marker");
|
||||
String prefix = request.getParameter("prefix");
|
||||
int maxUploads = 1000;
|
||||
int nextUploadId = 0;
|
||||
String nextKey = null;
|
||||
boolean isTruncated = false;
|
||||
S3MultipartUpload[] uploads = null;
|
||||
S3MultipartUpload onePart = null;
|
||||
|
||||
String temp = request.getParameter("max-uploads");
|
||||
if (null != temp) {
|
||||
maxUploads = Integer.parseInt( temp );
|
||||
if (maxUploads > 1000 || maxUploads < 0) maxUploads = 1000;
|
||||
}
|
||||
|
||||
// -> upload-id-marker is ignored unless key-marker is also specified
|
||||
String uploadIdMarker = request.getParameter("upload-id-marker");
|
||||
if (null == keyMarker) uploadIdMarker = null;
|
||||
|
||||
// -> does the bucket exist, we may need it to verify access permissions
|
||||
SBucketDao bucketDao = new SBucketDao();
|
||||
SBucket bucket = bucketDao.getByName(bucketName);
|
||||
if (bucket == null) {
|
||||
logger.error( "listMultipartUpload failed since " + bucketName + " does not exist" );
|
||||
response.setStatus(404);
|
||||
return;
|
||||
}
|
||||
|
||||
S3PolicyContext context = new S3PolicyContext( PolicyActions.ListBucketMultipartUploads, bucketName );
|
||||
context.setEvalParam( ConditionKeys.Prefix, prefix );
|
||||
context.setEvalParam( ConditionKeys.Delimiter, delimiter );
|
||||
S3Engine.verifyAccess( context, "SBucket", bucket.getId(), SAcl.PERMISSION_READ );
|
||||
|
||||
|
||||
// [B] Query the multipart table to get the list of current uploads
|
||||
try {
|
||||
MultipartLoadDao uploadDao = new MultipartLoadDao();
|
||||
OrderedPair<S3MultipartUpload[],Boolean> result = uploadDao.getInitiatedUploads( bucketName, maxUploads, prefix, keyMarker, uploadIdMarker );
|
||||
uploads = result.getFirst();
|
||||
isTruncated = result.getSecond().booleanValue();
|
||||
}
|
||||
catch( Exception e ) {
|
||||
logger.error("List Multipart Uploads failed due to " + e.getMessage(), e);
|
||||
response.setStatus(500);
|
||||
}
|
||||
|
||||
StringBuffer xml = new StringBuffer();
|
||||
xml.append( "<?xml version=\"1.0\" encoding=\"utf-8\"?>" );
|
||||
xml.append( "<ListMultipartUploadsResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">" );
|
||||
xml.append( "<Bucket>" ).append( bucketName ).append( "</Bucket>" );
|
||||
xml.append( "<KeyMarker>").append((null == keyMarker ? "" : keyMarker)).append( "</KeyMarker>" );
|
||||
xml.append( "<UploadIdMarker>").append((null == uploadIdMarker ? "" : uploadIdMarker)).append( "</UploadIdMarker>" );
|
||||
|
||||
|
||||
// [C] Construct the contents of the <Upload> element
|
||||
StringBuffer partsList = new StringBuffer();
|
||||
for( int i=0; i < uploads.length; i++ )
|
||||
{
|
||||
onePart = uploads[i];
|
||||
if (null == onePart) break;
|
||||
|
||||
if (delimiter != null && !delimiter.isEmpty())
|
||||
{
|
||||
// -> is this available only in the CommonPrefixes element?
|
||||
if (StringHelper.substringInBetween(onePart.getKey(), prefix, delimiter) != null)
|
||||
continue;
|
||||
}
|
||||
|
||||
nextKey = onePart.getKey();
|
||||
nextUploadId = onePart.getId();
|
||||
partsList.append( "<Upload>" );
|
||||
partsList.append( "<Key>" ).append( nextKey ).append( "</Key>" );
|
||||
partsList.append( "<UploadId>" ).append( nextUploadId ).append( "</UploadId>" );
|
||||
partsList.append( "<Initiator>" );
|
||||
partsList.append( "<ID>" ).append( onePart.getAccessKey()).append( "</ID>" );
|
||||
partsList.append( "<DisplayName></DisplayName>" );
|
||||
partsList.append( "</Initiator>" );
|
||||
partsList.append( "<Owner>" );
|
||||
partsList.append( "<ID>" ).append( onePart.getAccessKey()).append( "</ID>" );
|
||||
partsList.append( "<DisplayName></DisplayName>" );
|
||||
partsList.append( "</Owner>" );
|
||||
partsList.append( "<StorageClass>STANDARD</StorageClass>" );
|
||||
partsList.append( "<Initiated>" ).append( DatatypeConverter.printDateTime( onePart.getLastModified())).append( "</Initiated>" );
|
||||
partsList.append( "</Upload>" );
|
||||
}
|
||||
|
||||
// [D] Construct the contents of the <CommonPrefixes> elements (if any)
|
||||
for( int i=0; i < uploads.length; i++ )
|
||||
{
|
||||
onePart = uploads[i];
|
||||
if (null == onePart) break;
|
||||
|
||||
if (delimiter != null && !delimiter.isEmpty())
|
||||
{
|
||||
String subName = StringHelper.substringInBetween(onePart.getKey(), prefix, delimiter);
|
||||
if (subName != null)
|
||||
{
|
||||
partsList.append( "<CommonPrefixes>" );
|
||||
partsList.append( "<Prefix>" );
|
||||
if ( prefix != null && prefix.length() > 0 )
|
||||
partsList.append( prefix + delimiter + subName );
|
||||
else partsList.append( subName );
|
||||
partsList.append( "</Prefix>" );
|
||||
partsList.append( "</CommonPrefixes>" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// [D] Finish off the response
|
||||
xml.append( "<NextKeyMarker>" ).append((null == nextKey ? "" : nextKey)).append( "</NextKeyMarker>" );
|
||||
xml.append( "<NextUploadIdMarker>" ).append((0 == nextUploadId ? "" : nextUploadId)).append( "</NextUploadIdMarker>" );
|
||||
xml.append( "<MaxUploads>" ).append( maxUploads ).append( "</MaxUploads>" );
|
||||
xml.append( "<IsTruncated>" ).append( isTruncated ).append( "</IsTruncated>" );
|
||||
|
||||
xml.append( partsList.toString());
|
||||
xml.append( "</ListMultipartUploadsResult>" );
|
||||
|
||||
response.setStatus(200);
|
||||
response.setContentType("text/xml; charset=UTF-8");
|
||||
S3RestServlet.endResponse(response, xml.toString());
|
||||
}
|
||||
|
||||
private String streamToString( InputStream is ) throws IOException
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
if ( null != is )
|
||||
{
|
||||
Writer writer = new StringWriter();
|
||||
char[] buffer = new char[1024];
|
||||
try {
|
||||
Reader reader = new BufferedReader( new InputStreamReader(is, "UTF-8"));
|
||||
while ((n = reader.read(buffer)) != -1) writer.write(buffer, 0, n);
|
||||
}
|
||||
finally {
|
||||
is.close();
|
||||
}
|
||||
return writer.toString();
|
||||
}
|
||||
else return null;
|
||||
}
|
||||
}
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import javax.activation.DataHandler;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
<<<<<<< HEAD
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
|
|
@ -41,6 +42,13 @@ import javax.xml.stream.XMLStreamWriter;
|
|||
import org.apache.axiom.om.OMAbstractFactory;
|
||||
import org.apache.axiom.om.OMFactory;
|
||||
import org.apache.axis2.databinding.utils.writer.MTOMAwareXMLSerializer;
|
||||
=======
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
import org.apache.log4j.Logger;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
|
|
@ -48,16 +56,25 @@ import org.w3c.dom.NodeList;
|
|||
|
||||
import com.amazon.s3.CopyObjectResponse;
|
||||
import com.amazon.s3.GetObjectAccessControlPolicyResponse;
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
import com.cloud.bridge.io.MTOMAwareResultStreamWriter;
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
import com.cloud.bridge.model.SAcl;
|
||||
import com.cloud.bridge.model.SBucket;
|
||||
import com.cloud.bridge.persist.dao.MultipartLoadDao;
|
||||
import com.cloud.bridge.persist.dao.SBucketDao;
|
||||
import com.cloud.bridge.service.S3Constants;
|
||||
import com.cloud.bridge.service.S3RestServlet;
|
||||
<<<<<<< HEAD
|
||||
import com.cloud.bridge.service.S3SoapServiceImpl;
|
||||
import com.cloud.bridge.service.ServiceProvider;
|
||||
import com.cloud.bridge.service.ServletAction;
|
||||
import com.cloud.bridge.service.UserContext;
|
||||
=======
|
||||
import com.cloud.bridge.service.UserContext;
|
||||
import com.cloud.bridge.service.core.s3.S3AccessControlList;
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
import com.cloud.bridge.service.core.s3.S3AccessControlPolicy;
|
||||
import com.cloud.bridge.service.core.s3.S3AuthParams;
|
||||
import com.cloud.bridge.service.core.s3.S3ConditionalHeaders;
|
||||
|
|
@ -68,6 +85,10 @@ import com.cloud.bridge.service.core.s3.S3Engine;
|
|||
import com.cloud.bridge.service.core.s3.S3GetObjectAccessControlPolicyRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3GetObjectRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3GetObjectResponse;
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
import com.cloud.bridge.service.core.s3.S3Grant;
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
import com.cloud.bridge.service.core.s3.S3MetaDataEntry;
|
||||
import com.cloud.bridge.service.core.s3.S3MultipartPart;
|
||||
import com.cloud.bridge.service.core.s3.S3PolicyContext;
|
||||
|
|
@ -75,6 +96,10 @@ import com.cloud.bridge.service.core.s3.S3PutObjectInlineRequest;
|
|||
import com.cloud.bridge.service.core.s3.S3PutObjectInlineResponse;
|
||||
import com.cloud.bridge.service.core.s3.S3PutObjectRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3Response;
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
import com.cloud.bridge.service.core.s3.S3SetBucketAccessControlPolicyRequest;
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
import com.cloud.bridge.service.core.s3.S3SetObjectAccessControlPolicyRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3PolicyAction.PolicyActions;
|
||||
import com.cloud.bridge.service.exception.PermissionDeniedException;
|
||||
|
|
@ -82,17 +107,27 @@ import com.cloud.bridge.util.Converter;
|
|||
import com.cloud.bridge.util.DateHelper;
|
||||
import com.cloud.bridge.util.HeaderParam;
|
||||
import com.cloud.bridge.util.ServletRequestDataSource;
|
||||
<<<<<<< HEAD
|
||||
import com.cloud.bridge.util.Tuple;
|
||||
|
||||
/**
|
||||
* @author Kelven Yang
|
||||
=======
|
||||
import com.cloud.bridge.util.OrderedPair;
|
||||
|
||||
/**
|
||||
* @author Kelven Yang, John Zucker
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
*/
|
||||
public class S3ObjectAction implements ServletAction {
|
||||
protected final static Logger logger = Logger.getLogger(S3ObjectAction.class);
|
||||
|
||||
private DocumentBuilderFactory dbf = null;
|
||||
<<<<<<< HEAD
|
||||
private OMFactory factory = OMAbstractFactory.getOMFactory();
|
||||
private XMLOutputFactory xmlOutFactory = XMLOutputFactory.newInstance();
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
public S3ObjectAction() {
|
||||
dbf = DocumentBuilderFactory.newInstance();
|
||||
|
|
@ -104,7 +139,11 @@ public class S3ObjectAction implements ServletAction {
|
|||
throws IOException, XMLStreamException
|
||||
{
|
||||
String method = request.getMethod();
|
||||
<<<<<<< HEAD
|
||||
String queryString = request.getQueryString();
|
||||
=======
|
||||
String queryString = request.getQueryString();
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
String copy = null;
|
||||
|
||||
response.addHeader( "x-amz-request-id", UUID.randomUUID().toString());
|
||||
|
|
@ -128,7 +167,11 @@ public class S3ObjectAction implements ServletAction {
|
|||
else executePutObject(request, response);
|
||||
}
|
||||
else if ( null != (copy = request.getHeader( "x-amz-copy-source" )))
|
||||
<<<<<<< HEAD
|
||||
{
|
||||
=======
|
||||
{
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
executeCopyObject(request, response, copy.trim());
|
||||
}
|
||||
else executePutObject(request, response);
|
||||
|
|
@ -142,9 +185,15 @@ public class S3ObjectAction implements ServletAction {
|
|||
}
|
||||
else executeDeleteObject(request, response);
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
else if (method.equalsIgnoreCase( "HEAD" ))
|
||||
{
|
||||
executeHeadObject(request, response);
|
||||
=======
|
||||
else if (method.equalsIgnoreCase( "HEAD" ))
|
||||
{
|
||||
executeHeadObject(request, response);
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
else if (method.equalsIgnoreCase( "POST" ))
|
||||
{
|
||||
|
|
@ -153,7 +202,15 @@ public class S3ObjectAction implements ServletAction {
|
|||
if (queryString.contains("uploads")) executeInitiateMultipartUpload(request, response);
|
||||
else if (queryString.contains("uploadId")) executeCompleteMultipartUpload(request, response);
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
else executePostObject(request, response);
|
||||
=======
|
||||
else if ( request.getAttribute(S3Constants.PLAIN_POST_ACCESS_KEY) !=null )
|
||||
executePlainPostObject (request, response);
|
||||
// TODO - Having implemented the request, now provide an informative HTML page response
|
||||
else
|
||||
executePostObject(request, response);
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
else throw new IllegalArgumentException( "Unsupported method in REST request");
|
||||
}
|
||||
|
|
@ -171,7 +228,11 @@ public class S3ObjectAction implements ServletAction {
|
|||
String sourceKey = null;
|
||||
|
||||
// [A] Parse the x-amz-copy-source header into usable pieces
|
||||
<<<<<<< HEAD
|
||||
// -> is there a ?versionId= value
|
||||
=======
|
||||
// Check to find a ?versionId= value if any
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
int index = copy.indexOf( '?' );
|
||||
if (-1 != index)
|
||||
{
|
||||
|
|
@ -180,6 +241,7 @@ public class S3ObjectAction implements ServletAction {
|
|||
copy = copy.substring( 0, index );
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
// -> the value of copy should look like: "/bucket-name/object-name"
|
||||
index = copy.indexOf( '/' );
|
||||
if ( 0 != index )
|
||||
|
|
@ -189,6 +251,20 @@ public class S3ObjectAction implements ServletAction {
|
|||
index = copy.indexOf( '/' );
|
||||
if ( -1 == index )
|
||||
throw new IllegalArgumentException( "Invalid x-amz-copy-sourse header value [" + copy + "]" );
|
||||
=======
|
||||
// The value of copy should look like: "bucket-name/object-name"
|
||||
index = copy.indexOf( '/' );
|
||||
|
||||
// In case it looks like "/bucket-name/object-name" discard a leading '/' if it exists
|
||||
if ( 0 == index )
|
||||
{
|
||||
copy = copy.substring(1);
|
||||
index = copy.indexOf( '/' );
|
||||
}
|
||||
|
||||
if ( -1 == index )
|
||||
throw new IllegalArgumentException( "Invalid x-amz-copy-source header value [" + copy + "]" );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
sourceBucketName = copy.substring( 0, index );
|
||||
sourceKey = copy.substring( index+1 );
|
||||
|
|
@ -214,6 +290,7 @@ public class S3ObjectAction implements ServletAction {
|
|||
versionId = engineResponse.getPutVersion();
|
||||
if (null != versionId) response.addHeader( "x-amz-version-id", versionId );
|
||||
|
||||
<<<<<<< HEAD
|
||||
// -> serialize using the apache's Axiom classes
|
||||
CopyObjectResponse allBuckets = S3SoapServiceImpl.toCopyObjectResponse( engineResponse );
|
||||
|
||||
|
|
@ -231,6 +308,25 @@ public class S3ObjectAction implements ServletAction {
|
|||
}
|
||||
|
||||
private void executeGetObjectAcl(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
=======
|
||||
// To allow the copy object result to be serialized via Axiom classes
|
||||
CopyObjectResponse allBuckets = S3SerializableServiceImplementation.toCopyObjectResponse( engineResponse );
|
||||
|
||||
OutputStream outputStream = response.getOutputStream();
|
||||
response.setStatus(200);
|
||||
response.setContentType("application/xml");
|
||||
// The content-type literally should be "application/xml; charset=UTF-8"
|
||||
// but any compliant JVM supplies utf-8 by default;
|
||||
|
||||
MTOMAwareResultStreamWriter resultWriter = new MTOMAwareResultStreamWriter ("CopyObjectResult", outputStream );
|
||||
resultWriter.startWrite();
|
||||
resultWriter.writeout(allBuckets);
|
||||
resultWriter.stopWrite();
|
||||
|
||||
}
|
||||
|
||||
private void executeGetObjectAcl(HttpServletRequest request, HttpServletResponse response) throws IOException, XMLStreamException
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
{
|
||||
String bucketName = (String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
|
||||
String key = (String)request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
|
||||
|
|
@ -253,6 +349,7 @@ public class S3ObjectAction implements ServletAction {
|
|||
if (null != version) response.addHeader( "x-amz-version-id", version );
|
||||
|
||||
|
||||
<<<<<<< HEAD
|
||||
// -> serialize using the apache's Axiom classes
|
||||
GetObjectAccessControlPolicyResponse onePolicy = S3SoapServiceImpl.toGetObjectAccessControlPolicyResponse( engineResponse );
|
||||
|
||||
|
|
@ -302,12 +399,78 @@ public class S3ObjectAction implements ServletAction {
|
|||
String version = engineResponse.getVersion();
|
||||
if (null != version) response.addHeader( "x-amz-version-id", version );
|
||||
response.setStatus( engineResponse.getResultCode());
|
||||
=======
|
||||
// To allow the get object acl policy result to be serialized via Axiom classes
|
||||
GetObjectAccessControlPolicyResponse onePolicy = S3SerializableServiceImplementation.toGetObjectAccessControlPolicyResponse( engineResponse );
|
||||
|
||||
OutputStream outputStream = response.getOutputStream();
|
||||
response.setStatus(200);
|
||||
response.setContentType("application/xml");
|
||||
// The content-type literally should be "application/xml; charset=UTF-8"
|
||||
// but any compliant JVM supplies utf-8 by default;
|
||||
|
||||
MTOMAwareResultStreamWriter resultWriter = new MTOMAwareResultStreamWriter ("GetObjectAccessControlPolicyResult", outputStream );
|
||||
resultWriter.startWrite();
|
||||
resultWriter.writeout(onePolicy);
|
||||
resultWriter.stopWrite();
|
||||
}
|
||||
|
||||
private void executePutObjectAcl(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
// [A] Determine that there is an applicable bucket which might have an ACL set
|
||||
|
||||
String bucketName = (String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
|
||||
String key = (String)request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
|
||||
|
||||
SBucketDao bucketDao = new SBucketDao();
|
||||
SBucket bucket = bucketDao.getByName( bucketName );
|
||||
String owner = null;
|
||||
if ( null != bucket )
|
||||
owner = bucket.getOwnerCanonicalId();
|
||||
if (null == owner)
|
||||
{
|
||||
logger.error( "ACL update failed since " + bucketName + " does not exist" );
|
||||
throw new IOException("ACL update failed");
|
||||
}
|
||||
if (null == key)
|
||||
{
|
||||
logger.error( "ACL update failed since " + bucketName + " does not contain the expected key" );
|
||||
throw new IOException("ACL update failed");
|
||||
}
|
||||
|
||||
// [B] Obtain the grant request which applies to the acl request string. This latter is supplied as the value of the x-amz-acl header.
|
||||
|
||||
S3SetObjectAccessControlPolicyRequest engineRequest = new S3SetObjectAccessControlPolicyRequest();
|
||||
S3Grant grantRequest = new S3Grant();
|
||||
S3AccessControlList aclRequest = new S3AccessControlList();
|
||||
|
||||
String aclRequestString = request.getHeader("x-amz-acl");
|
||||
OrderedPair <Integer,Integer> accessControlsForObjectOwner = SAcl.getCannedAccessControls(aclRequestString,"SObject");
|
||||
grantRequest.setPermission(accessControlsForObjectOwner.getFirst());
|
||||
grantRequest.setGrantee(accessControlsForObjectOwner.getSecond());
|
||||
grantRequest.setCanonicalUserID(owner);
|
||||
aclRequest.addGrant(grantRequest);
|
||||
engineRequest.setAcl(aclRequest);
|
||||
engineRequest.setBucketName(bucketName);
|
||||
engineRequest.setKey(key);
|
||||
|
||||
|
||||
// [C] Allow an S3Engine to handle the S3SetObjectAccessControlPolicyRequest
|
||||
S3Response engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest(engineRequest);
|
||||
response.setStatus( engineResponse.getResultCode());
|
||||
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
||||
private void executeGetObject(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
|
||||
<<<<<<< HEAD
|
||||
String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
|
||||
=======
|
||||
String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
|
||||
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
S3GetObjectRequest engineRequest = new S3GetObjectRequest();
|
||||
engineRequest.setBucketName(bucket);
|
||||
|
|
@ -361,7 +524,10 @@ public class S3ObjectAction implements ServletAction {
|
|||
S3RestServlet.writeResponse(response, "HTTP/1.1 100 Continue\r\n");
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
String contentType = request.getHeader( "Content-Type" );
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
long contentLength = Converter.toLong(request.getHeader("Content-Length"), 0);
|
||||
|
||||
String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
|
||||
|
|
@ -405,6 +571,57 @@ public class S3ObjectAction implements ServletAction {
|
|||
String version = engineRequest.getVersion();
|
||||
if (null != version) response.addHeader( "x-amz-version-id", version );
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
/*
|
||||
* The purpose of a plain POST operation is to add an object to a specified bucket using HTML forms.
|
||||
* The capability is for developer and tester convenience providing a simple browser-based upload
|
||||
* feature as an alternative to using PUTs.
|
||||
* In the case of PUTs the upload information is passed through HTTP headers. However in the case of a
|
||||
* POST this information must be supplied as form fields. Many of these are mandatory or otherwise
|
||||
* the POST request will be rejected.
|
||||
* The requester using the HTML page must submit valid credentials sufficient for checking that
|
||||
* the bucket to which the object is to be added has WRITE permission for that user. The AWS access
|
||||
* key field on the form is taken to be synonymous with the user canonical ID for this purpose.
|
||||
*/
|
||||
private void executePlainPostObject(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
String continueHeader = request.getHeader( "Expect" );
|
||||
if (continueHeader != null && continueHeader.equalsIgnoreCase("100-continue")) {
|
||||
S3RestServlet.writeResponse(response, "HTTP/1.1 100 Continue\r\n");
|
||||
}
|
||||
|
||||
long contentLength = Converter.toLong(request.getHeader("Content-Length"), 0);
|
||||
|
||||
String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
|
||||
String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
|
||||
String accessKey = (String) request.getAttribute(S3Constants.PLAIN_POST_ACCESS_KEY);
|
||||
String signature = (String) request.getAttribute(S3Constants.PLAIN_POST_SIGNATURE);
|
||||
S3Grant grant = new S3Grant();
|
||||
grant.setCanonicalUserID(accessKey);
|
||||
grant.setGrantee(SAcl.GRANTEE_USER);
|
||||
grant.setPermission(SAcl.PERMISSION_FULL);
|
||||
S3AccessControlList acl = new S3AccessControlList();
|
||||
acl.addGrant(grant);
|
||||
S3PutObjectInlineRequest engineRequest = new S3PutObjectInlineRequest();
|
||||
engineRequest.setBucketName(bucket);
|
||||
engineRequest.setKey(key);
|
||||
engineRequest.setAcl(acl);
|
||||
engineRequest.setContentLength(contentLength);
|
||||
engineRequest.setMetaEntries( extractMetaData( request ));
|
||||
engineRequest.setCannedAccess( request.getHeader( "x-amz-acl" ));
|
||||
|
||||
DataHandler dataHandler = new DataHandler(new ServletRequestDataSource(request));
|
||||
engineRequest.setData(dataHandler);
|
||||
|
||||
S3PutObjectInlineResponse engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest(engineRequest);
|
||||
response.setHeader("ETag", "\"" + engineResponse.getETag() + "\"");
|
||||
String version = engineResponse.getVersion();
|
||||
if (null != version) response.addHeader( "x-amz-version-id", version );
|
||||
}
|
||||
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
private void executeHeadObject(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
|
|
@ -459,7 +676,13 @@ public class S3ObjectAction implements ServletAction {
|
|||
// they are not HTTP request headers). All the values we used to get in the request headers
|
||||
// are not encoded in the request body.
|
||||
//
|
||||
<<<<<<< HEAD
|
||||
public void executePostObject( HttpServletRequest request, HttpServletResponse response ) throws IOException
|
||||
=======
|
||||
// add ETag header computed as Base64 MD5 whenever object is uploaded or updated
|
||||
//
|
||||
private void executePostObject( HttpServletRequest request, HttpServletResponse response ) throws IOException
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
{
|
||||
String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
|
||||
String contentType = request.getHeader( "Content-Type" );
|
||||
|
|
@ -595,7 +818,11 @@ public class S3ObjectAction implements ServletAction {
|
|||
*/
|
||||
private void executeInitiateMultipartUpload( HttpServletRequest request, HttpServletResponse response ) throws IOException
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
// -> this request is via a POST which typically has its auth parameters inside the message
|
||||
=======
|
||||
// This request is via a POST which typically has its auth parameters inside the message
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
try {
|
||||
S3RestServlet.authenticateRequest( request, S3RestServlet.extractRequestHeaders( request ));
|
||||
}
|
||||
|
|
@ -646,8 +873,11 @@ public class S3ObjectAction implements ServletAction {
|
|||
|
||||
long contentLength = Converter.toLong(request.getHeader("Content-Length"), 0);
|
||||
|
||||
<<<<<<< HEAD
|
||||
String md5 = request.getHeader( "Content-MD5" );
|
||||
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
String temp = request.getParameter("uploadId");
|
||||
if (null != temp) uploadId = Integer.parseInt( temp );
|
||||
|
||||
|
|
@ -716,8 +946,15 @@ public class S3ObjectAction implements ServletAction {
|
|||
String cannedAccess = null;
|
||||
int uploadId = -1;
|
||||
|
||||
<<<<<<< HEAD
|
||||
// -> Amazon defines to keep connection alive by sending whitespace characters until done
|
||||
OutputStream os = response.getOutputStream();
|
||||
=======
|
||||
// AWS S3 specifies that the keep alive connection is by sending whitespace characters until done
|
||||
// Therefore the XML version prolog is prepended to the stream in advance
|
||||
OutputStream outputStream = response.getOutputStream();
|
||||
outputStream.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>".getBytes());
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
String temp = request.getParameter("uploadId");
|
||||
if (null != temp) uploadId = Integer.parseInt( temp );
|
||||
|
|
@ -728,7 +965,11 @@ public class S3ObjectAction implements ServletAction {
|
|||
MultipartLoadDao uploadDao = new MultipartLoadDao();
|
||||
if (null == uploadDao.multipartExits( uploadId )) {
|
||||
response.setStatus(404);
|
||||
<<<<<<< HEAD
|
||||
returnErrorXML( 404, "NotFound", os );
|
||||
=======
|
||||
returnErrorXML( 404, "NotFound", outputStream );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -736,7 +977,11 @@ public class S3ObjectAction implements ServletAction {
|
|||
String initiator = uploadDao.getInitiator( uploadId );
|
||||
if (null == initiator || !initiator.equals( UserContext.current().getAccessKey())) {
|
||||
response.setStatus(403);
|
||||
<<<<<<< HEAD
|
||||
returnErrorXML( 403, "Forbidden", os );
|
||||
=======
|
||||
returnErrorXML( 403, "Forbidden", outputStream );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -747,16 +992,27 @@ public class S3ObjectAction implements ServletAction {
|
|||
catch( Exception e ) {
|
||||
logger.error("executeCompleteMultipartUpload failed due to " + e.getMessage(), e);
|
||||
response.setStatus(500);
|
||||
<<<<<<< HEAD
|
||||
returnErrorXML( 500, "InternalError", os );
|
||||
=======
|
||||
returnErrorXML( 500, "InternalError", outputStream );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// [C] Parse the given XML body part and perform error checking
|
||||
<<<<<<< HEAD
|
||||
Tuple<Integer,String> match = verifyParts( request.getInputStream(), parts );
|
||||
if (200 != match.getFirst().intValue()) {
|
||||
response.setStatus(match.getFirst().intValue());
|
||||
returnErrorXML( match.getFirst().intValue(), match.getSecond(), os );
|
||||
=======
|
||||
OrderedPair<Integer,String> match = verifyParts( request.getInputStream(), parts );
|
||||
if (200 != match.getFirst().intValue()) {
|
||||
response.setStatus(match.getFirst().intValue());
|
||||
returnErrorXML( match.getFirst().intValue(), match.getSecond(), outputStream );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -768,26 +1024,48 @@ public class S3ObjectAction implements ServletAction {
|
|||
engineRequest.setMetaEntries(meta);
|
||||
engineRequest.setCannedAccess(cannedAccess);
|
||||
|
||||
<<<<<<< HEAD
|
||||
S3PutObjectInlineResponse engineResponse = ServiceProvider.getInstance().getS3Engine().concatentateMultipartUploads( response, engineRequest, parts, os );
|
||||
=======
|
||||
S3PutObjectInlineResponse engineResponse = ServiceProvider.getInstance().getS3Engine().concatentateMultipartUploads( response, engineRequest, parts, outputStream );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
int result = engineResponse.getResultCode();
|
||||
// -> free all multipart state since we now have one concatentated object
|
||||
if (200 == result) ServiceProvider.getInstance().getS3Engine().freeUploadParts( bucket, uploadId, false );
|
||||
|
||||
<<<<<<< HEAD
|
||||
// -> if all successful then clean up all left over parts
|
||||
if ( 200 == result )
|
||||
{
|
||||
StringBuffer xml = new StringBuffer();
|
||||
xml.append( "<?xml version=\"1.0\" encoding=\"utf-8\"?>" );
|
||||
=======
|
||||
// If all successful then clean up all left over parts
|
||||
// Notice that "<?xml version=\"1.0\" encoding=\"utf-8\"?>" has already been written into the servlet output stream at the beginning of section [A]
|
||||
if ( 200 == result )
|
||||
{
|
||||
StringBuffer xml = new StringBuffer();
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
xml.append( "<CompleteMultipartUploadResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">" );
|
||||
xml.append( "<Location>" ).append( "http://" + bucket + ".s3.amazonaws.com/" + key ).append( "</Location>" );
|
||||
xml.append( "<Bucket>" ).append( bucket ).append( "</Bucket>" );
|
||||
xml.append( "<Key>" ).append( key ).append( "</Key>" );
|
||||
<<<<<<< HEAD
|
||||
xml.append( "<ETag>\"" ).append( engineResponse.getETag()).append( "\"</<ETag>" );
|
||||
xml.append( "</CompleteMultipartUploadResult>" );
|
||||
os.write( xml.toString().getBytes());
|
||||
os.close();
|
||||
}
|
||||
else returnErrorXML( result, null, os );
|
||||
=======
|
||||
xml.append( "<ETag>\"" ).append( engineResponse.getETag()).append( "\"</ETag>" );
|
||||
xml.append( "</CompleteMultipartUploadResult>" );
|
||||
String xmlString = xml.toString().replaceAll("^\\s+", ""); // Remove leading whitespace characters
|
||||
outputStream.write( xmlString.getBytes());
|
||||
outputStream.close();
|
||||
}
|
||||
else returnErrorXML( result, null, outputStream );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
||||
private void executeAbortMultipartUpload( HttpServletRequest request, HttpServletResponse response ) throws IOException
|
||||
|
|
@ -839,7 +1117,11 @@ public class S3ObjectAction implements ServletAction {
|
|||
|
||||
try {
|
||||
MultipartLoadDao uploadDao = new MultipartLoadDao();
|
||||
<<<<<<< HEAD
|
||||
Tuple<String,String> exists = uploadDao.multipartExits( uploadId );
|
||||
=======
|
||||
OrderedPair<String,String> exists = uploadDao.multipartExits( uploadId );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
if (null == exists) {
|
||||
response.setStatus(404);
|
||||
return;
|
||||
|
|
@ -1121,7 +1403,11 @@ public class S3ObjectAction implements ServletAction {
|
|||
* @return error code, and error string
|
||||
* @throws ParserConfigurationException, IOException, SAXException
|
||||
*/
|
||||
<<<<<<< HEAD
|
||||
private Tuple<Integer,String> verifyParts( InputStream is, S3MultipartPart[] parts )
|
||||
=======
|
||||
private OrderedPair<Integer,String> verifyParts( InputStream is, S3MultipartPart[] parts )
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
{
|
||||
try {
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
|
|
@ -1146,7 +1432,11 @@ public class S3ObjectAction implements ServletAction {
|
|||
nodeSet = doc.getElementsByTagName( "Part" );
|
||||
count = nodeSet.getLength();
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
if (count != parts.length) return new Tuple<Integer, String>(400, "InvalidPart");
|
||||
=======
|
||||
if (count != parts.length) return new OrderedPair<Integer, String>(400, "InvalidPart");
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
// -> get a list of all the children elements of the 'Part' parent element
|
||||
for( int i=0; i < count; i++ )
|
||||
|
|
@ -1178,20 +1468,35 @@ public class S3ObjectAction implements ServletAction {
|
|||
|
||||
// -> do the parts given in the call XML match what was previously uploaded?
|
||||
if (lastNumber >= partNumber) {
|
||||
<<<<<<< HEAD
|
||||
return new Tuple<Integer, String>(400, "InvalidPartOrder");
|
||||
=======
|
||||
return new OrderedPair<Integer, String>(400, "InvalidPartOrder");
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
if (partNumber != parts[i].getPartNumber() ||
|
||||
eTag == null ||
|
||||
!eTag.equalsIgnoreCase( "\"" + parts[i].getETag() + "\"" )) {
|
||||
<<<<<<< HEAD
|
||||
return new Tuple<Integer, String>(400, "InvalidPart");
|
||||
=======
|
||||
return new OrderedPair<Integer, String>(400, "InvalidPart");
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
||||
lastNumber = partNumber;
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
return new Tuple<Integer, String>(200, "Success");
|
||||
}
|
||||
catch( Exception e ) {
|
||||
return new Tuple<Integer, String>(500, e.toString());
|
||||
=======
|
||||
return new OrderedPair<Integer, String>(200, "Success");
|
||||
}
|
||||
catch( Exception e ) {
|
||||
return new OrderedPair<Integer, String>(500, e.toString());
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,724 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.cloud.bridge.service.controller.s3;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
import org.apache.axis2.AxisFault;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.amazon.s3.AccessControlList;
|
||||
import com.amazon.s3.AccessControlPolicy;
|
||||
import com.amazon.s3.AmazonS3SkeletonInterface;
|
||||
import com.amazon.s3.CanonicalUser;
|
||||
import com.amazon.s3.CopyObject;
|
||||
import com.amazon.s3.CopyObjectResult;
|
||||
import com.amazon.s3.Group;
|
||||
import com.amazon.s3.CopyObjectResponse;
|
||||
import com.amazon.s3.CreateBucket;
|
||||
import com.amazon.s3.CreateBucketResponse;
|
||||
import com.amazon.s3.CreateBucketResult;
|
||||
import com.amazon.s3.DeleteBucket;
|
||||
import com.amazon.s3.DeleteBucketResponse;
|
||||
import com.amazon.s3.DeleteObject;
|
||||
import com.amazon.s3.DeleteObjectResponse;
|
||||
import com.amazon.s3.GetBucketAccessControlPolicy;
|
||||
import com.amazon.s3.GetBucketAccessControlPolicyResponse;
|
||||
import com.amazon.s3.GetBucketLoggingStatus;
|
||||
import com.amazon.s3.GetBucketLoggingStatusResponse;
|
||||
import com.amazon.s3.GetObject;
|
||||
import com.amazon.s3.GetObjectAccessControlPolicy;
|
||||
import com.amazon.s3.GetObjectAccessControlPolicyResponse;
|
||||
import com.amazon.s3.GetObjectExtended;
|
||||
import com.amazon.s3.GetObjectExtendedResponse;
|
||||
import com.amazon.s3.GetObjectResponse;
|
||||
import com.amazon.s3.GetObjectResult;
|
||||
import com.amazon.s3.Grant;
|
||||
import com.amazon.s3.Grantee;
|
||||
import com.amazon.s3.ListAllMyBuckets;
|
||||
import com.amazon.s3.ListAllMyBucketsEntry;
|
||||
import com.amazon.s3.ListAllMyBucketsList;
|
||||
import com.amazon.s3.ListAllMyBucketsResponse;
|
||||
import com.amazon.s3.ListAllMyBucketsResult;
|
||||
import com.amazon.s3.ListBucket;
|
||||
import com.amazon.s3.ListBucketResponse;
|
||||
import com.amazon.s3.ListBucketResult;
|
||||
import com.amazon.s3.ListEntry;
|
||||
import com.amazon.s3.MetadataDirective;
|
||||
import com.amazon.s3.MetadataEntry;
|
||||
import com.amazon.s3.Permission;
|
||||
import com.amazon.s3.PrefixEntry;
|
||||
import com.amazon.s3.PutObject;
|
||||
import com.amazon.s3.PutObjectInline;
|
||||
import com.amazon.s3.PutObjectInlineResponse;
|
||||
import com.amazon.s3.PutObjectResponse;
|
||||
import com.amazon.s3.PutObjectResult;
|
||||
import com.amazon.s3.SetBucketAccessControlPolicy;
|
||||
import com.amazon.s3.SetBucketAccessControlPolicyResponse;
|
||||
import com.amazon.s3.SetBucketLoggingStatus;
|
||||
import com.amazon.s3.SetBucketLoggingStatusResponse;
|
||||
import com.amazon.s3.SetObjectAccessControlPolicy;
|
||||
import com.amazon.s3.SetObjectAccessControlPolicyResponse;
|
||||
import com.amazon.s3.Status;
|
||||
import com.amazon.s3.StorageClass;
|
||||
import com.cloud.bridge.model.SAcl;
|
||||
import com.cloud.bridge.service.core.s3.S3AccessControlList;
|
||||
import com.cloud.bridge.service.core.s3.S3AccessControlPolicy;
|
||||
import com.cloud.bridge.service.core.s3.S3CanonicalUser;
|
||||
import com.cloud.bridge.service.core.s3.S3ConditionalHeaders;
|
||||
import com.cloud.bridge.service.core.s3.S3CopyObjectRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3CopyObjectResponse;
|
||||
import com.cloud.bridge.service.core.s3.S3CreateBucketRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3CreateBucketResponse;
|
||||
import com.cloud.bridge.service.core.s3.S3DeleteBucketRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3DeleteObjectRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3Engine;
|
||||
import com.cloud.bridge.service.core.s3.S3GetBucketAccessControlPolicyRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3GetObjectAccessControlPolicyRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3GetObjectRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3GetObjectResponse;
|
||||
import com.cloud.bridge.service.core.s3.S3Grant;
|
||||
import com.cloud.bridge.service.core.s3.S3ListAllMyBucketsEntry;
|
||||
import com.cloud.bridge.service.core.s3.S3ListAllMyBucketsRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3ListAllMyBucketsResponse;
|
||||
import com.cloud.bridge.service.core.s3.S3ListBucketObjectEntry;
|
||||
import com.cloud.bridge.service.core.s3.S3ListBucketPrefixEntry;
|
||||
import com.cloud.bridge.service.core.s3.S3ListBucketRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3ListBucketResponse;
|
||||
import com.cloud.bridge.service.core.s3.S3MetaDataEntry;
|
||||
import com.cloud.bridge.service.core.s3.S3PutObjectInlineRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3PutObjectInlineResponse;
|
||||
import com.cloud.bridge.service.core.s3.S3Response;
|
||||
import com.cloud.bridge.service.core.s3.S3SetBucketAccessControlPolicyRequest;
|
||||
import com.cloud.bridge.service.core.s3.S3SetObjectAccessControlPolicyRequest;
|
||||
import com.cloud.bridge.service.exception.InternalErrorException;
|
||||
|
||||
/* @Author Kelven Yang, John Zucker
|
||||
* Implementation of S3 service requests as operations defined by the interface, com.amazon.s3.AmazonS3SkeletonInterface.
|
||||
* The operations dispatched from this class are of the form of SOAP operations which define business logic to be executed by the request.
|
||||
* The methods required for S3 services in accordance with the skeleton are either implementations of the following
|
||||
* getBucketLoggingStatus
|
||||
* copyObject
|
||||
* getBucketAccessControlPolicy
|
||||
* listBucket
|
||||
* putObject
|
||||
* createBucket
|
||||
* listAllMyBuckets
|
||||
* getObject
|
||||
* deleteBucket
|
||||
* setBucketLoggingStatus
|
||||
* getObjectAccessControlPolicy
|
||||
* deleteObject
|
||||
* setBucketAccessControlPolicy
|
||||
* setObjectAccessControlPolicy
|
||||
* putObjectInline
|
||||
* getObjectExtended
|
||||
* or throw and Axis2 fault otherwise.
|
||||
* These skeleton methods can be used as the implementation of services to satisfy SOAP calls, but also to provide the output
|
||||
* to be serialized by the AXIOM XML processor.
|
||||
*
|
||||
* */
|
||||
|
||||
public class S3SerializableServiceImplementation implements AmazonS3SkeletonInterface {
|
||||
protected final static Logger logger = Logger.getLogger(S3SerializableServiceImplementation.class);
|
||||
|
||||
private S3Engine engine;
|
||||
|
||||
public S3SerializableServiceImplementation(S3Engine engine) {
|
||||
this.engine = engine;
|
||||
}
|
||||
|
||||
public GetBucketLoggingStatusResponse getBucketLoggingStatus(
|
||||
GetBucketLoggingStatus getBucketLoggingStatus) {
|
||||
throw new UnsupportedOperationException("Unsupported API");
|
||||
}
|
||||
|
||||
public SetBucketLoggingStatusResponse setBucketLoggingStatus(SetBucketLoggingStatus setBucketLoggingStatus) {
|
||||
throw new UnsupportedOperationException("Unsupported API");
|
||||
}
|
||||
|
||||
public CopyObjectResponse copyObject(CopyObject copyObject) throws AxisFault {
|
||||
S3CopyObjectRequest request = new S3CopyObjectRequest();
|
||||
|
||||
request.setSourceBucketName(copyObject.getSourceBucket());
|
||||
request.setSourceKey(copyObject.getSourceKey());
|
||||
request.setDestinationBucketName(copyObject.getDestinationBucket());
|
||||
request.setDestinationKey(copyObject.getDestinationKey());
|
||||
|
||||
MetadataDirective mdd = copyObject.getMetadataDirective();
|
||||
if (null != mdd) request.setDataDirective(mdd.getValue());
|
||||
|
||||
request.setMetaEntries(toEngineMetaEntries(copyObject.getMetadata()));
|
||||
request.setAcl(toEngineAccessControlList(copyObject.getAccessControlList()));
|
||||
|
||||
S3ConditionalHeaders conds = new S3ConditionalHeaders();
|
||||
conds.setModifiedSince(copyObject.getCopySourceIfModifiedSince());
|
||||
conds.setUnModifiedSince(copyObject.getCopySourceIfUnmodifiedSince());
|
||||
conds.setMatch(copyObject.getCopySourceIfMatch());
|
||||
conds.setNoneMatch(copyObject.getCopySourceIfNoneMatch());
|
||||
request.setConditions(conds);
|
||||
|
||||
return toCopyObjectResponse(engine.handleRequest(request));
|
||||
}
|
||||
|
||||
public GetBucketAccessControlPolicyResponse getBucketAccessControlPolicy(
|
||||
GetBucketAccessControlPolicy getBucketAccessControlPolicy) {
|
||||
// TODO - after authentication, we should setup user context
|
||||
return toGetBucketAccessControlPolicyResponse(engine.handleRequest(
|
||||
toEngineGetBucketAccessControlPolicyRequest(getBucketAccessControlPolicy)));
|
||||
}
|
||||
|
||||
private S3GetBucketAccessControlPolicyRequest toEngineGetBucketAccessControlPolicyRequest(
|
||||
GetBucketAccessControlPolicy getBucketAccessControlPolicy) {
|
||||
S3GetBucketAccessControlPolicyRequest request = new S3GetBucketAccessControlPolicyRequest();
|
||||
|
||||
request.setAccessKey(getBucketAccessControlPolicy.getAWSAccessKeyId());
|
||||
request.setRequestTimestamp(getBucketAccessControlPolicy.getTimestamp());
|
||||
request.setSignature(getBucketAccessControlPolicy.getSignature());
|
||||
request.setBucketName(getBucketAccessControlPolicy.getBucket());
|
||||
return request;
|
||||
}
|
||||
|
||||
public static GetBucketAccessControlPolicyResponse toGetBucketAccessControlPolicyResponse(S3AccessControlPolicy policy) {
|
||||
GetBucketAccessControlPolicyResponse response = new GetBucketAccessControlPolicyResponse();
|
||||
response.setGetBucketAccessControlPolicyResponse(toAccessControlPolicy(policy));
|
||||
return response;
|
||||
}
|
||||
|
||||
public SetBucketAccessControlPolicyResponse setBucketAccessControlPolicy(SetBucketAccessControlPolicy setBucketAccessControlPolicy) {
|
||||
S3SetBucketAccessControlPolicyRequest request = new S3SetBucketAccessControlPolicyRequest();
|
||||
request.setAccessKey(setBucketAccessControlPolicy.getAWSAccessKeyId());
|
||||
request.setRequestTimestamp(setBucketAccessControlPolicy.getTimestamp());
|
||||
request.setSignature(setBucketAccessControlPolicy.getSignature());
|
||||
request.setBucketName(setBucketAccessControlPolicy.getBucket());
|
||||
request.setAcl(toEngineAccessControlList(setBucketAccessControlPolicy.getAccessControlList()));
|
||||
|
||||
SetBucketAccessControlPolicyResponse response = new SetBucketAccessControlPolicyResponse();
|
||||
return response;
|
||||
}
|
||||
|
||||
public ListBucketResponse listBucket (ListBucket listBucket) {
|
||||
// after authentication, we should setup user context
|
||||
return toListBucketResponse(engine.listBucketContents(toEngineListBucketRequest(listBucket), false));
|
||||
}
|
||||
|
||||
private S3ListBucketRequest toEngineListBucketRequest(ListBucket listBucket) {
|
||||
S3ListBucketRequest request = new S3ListBucketRequest();
|
||||
|
||||
request.setAccessKey(listBucket.getAWSAccessKeyId());
|
||||
request.setRequestTimestamp(listBucket.getTimestamp());
|
||||
request.setSignature(listBucket.getSignature());
|
||||
|
||||
request.setBucketName(listBucket.getBucket());
|
||||
request.setDelimiter(listBucket.getDelimiter());
|
||||
request.setMarker(listBucket.getMarker());
|
||||
request.setMaxKeys(listBucket.getMaxKeys());
|
||||
request.setPrefix(listBucket.getPrefix());
|
||||
return request;
|
||||
}
|
||||
|
||||
public static ListBucketResponse toListBucketResponse(S3ListBucketResponse engineResponse) {
|
||||
ListBucketResponse response = new ListBucketResponse();
|
||||
ListBucketResult result = new ListBucketResult();
|
||||
result.setName(engineResponse.getBucketName());
|
||||
result.setDelimiter(engineResponse.getDelimiter());
|
||||
result.setPrefix(engineResponse.getPrefix());
|
||||
result.setMarker(engineResponse.getMarker());
|
||||
result.setMaxKeys(engineResponse.getMaxKeys());
|
||||
result.setIsTruncated(engineResponse.isTruncated());
|
||||
result.setNextMarker(engineResponse.getNextMarker());
|
||||
result.setCommonPrefixes(toPrefixEntry(engineResponse.getCommonPrefixes()));
|
||||
result.setContents(toListEntry(engineResponse.getContents()));
|
||||
response.setListBucketResponse(result);
|
||||
return response;
|
||||
}
|
||||
|
||||
private static PrefixEntry[] toPrefixEntry(S3ListBucketPrefixEntry[] engineEntries) {
|
||||
if(engineEntries != null) {
|
||||
PrefixEntry[] entries = new PrefixEntry[engineEntries.length];
|
||||
for(int i = 0; i < engineEntries.length; i++) {
|
||||
entries[i] = new PrefixEntry();
|
||||
entries[i].setPrefix(engineEntries[i].getPrefix());
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static ListEntry[] toListEntry(S3ListBucketObjectEntry[] engineEntries) {
|
||||
if(engineEntries != null) {
|
||||
ListEntry[] entries = new ListEntry[engineEntries.length];
|
||||
for(int i = 0; i < engineEntries.length; i++) {
|
||||
entries[i] = new ListEntry();
|
||||
entries[i].setETag(engineEntries[i].getETag());
|
||||
entries[i].setKey(engineEntries[i].getKey());
|
||||
entries[i].setLastModified(engineEntries[i].getLastModified());
|
||||
entries[i].setSize(engineEntries[i].getSize());
|
||||
entries[i].setStorageClass(StorageClass.STANDARD);
|
||||
|
||||
CanonicalUser owner = new CanonicalUser();
|
||||
owner.setID(engineEntries[i].getOwnerCanonicalId());
|
||||
owner.setDisplayName(engineEntries[i].getOwnerDisplayName());
|
||||
entries[i].setOwner(owner);
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public PutObjectResponse putObject(PutObject putObject) {
|
||||
//TODO : fill this with the necessary business logic
|
||||
throw new UnsupportedOperationException("Please implement " + this.getClass().getName() + "#putObject");
|
||||
}
|
||||
|
||||
public CreateBucketResponse createBucket (CreateBucket createBucket) {
|
||||
return toCreateBucketResponse(engine.handleRequest(toEngineCreateBucketRequest(createBucket)));
|
||||
}
|
||||
|
||||
private S3CreateBucketRequest toEngineCreateBucketRequest(CreateBucket createBucket) {
|
||||
S3CreateBucketRequest request = new S3CreateBucketRequest();
|
||||
request.setAccessKey(createBucket.getAWSAccessKeyId());
|
||||
request.setRequestTimestamp(createBucket.getTimestamp());
|
||||
request.setSignature(createBucket.getSignature());
|
||||
request.setBucketName(createBucket.getBucket());
|
||||
request.setAcl(toEngineAccessControlList(createBucket.getAccessControlList()));
|
||||
return request;
|
||||
}
|
||||
|
||||
private CreateBucketResponse toCreateBucketResponse(S3CreateBucketResponse engineResponse) {
|
||||
CreateBucketResponse response = new CreateBucketResponse();
|
||||
CreateBucketResult result = new CreateBucketResult();
|
||||
result.setBucketName(engineResponse.getBucketName());
|
||||
response.setCreateBucketReturn(result);
|
||||
return response;
|
||||
}
|
||||
|
||||
public ListAllMyBucketsResponse listAllMyBuckets (ListAllMyBuckets listAllMyBuckets) {
|
||||
return toListAllMyBucketsResponse(engine.handleRequest(toEngineListAllMyBucketsRequest(listAllMyBuckets)));
|
||||
}
|
||||
|
||||
private S3ListAllMyBucketsRequest toEngineListAllMyBucketsRequest(ListAllMyBuckets listAllMyBuckets) {
|
||||
S3ListAllMyBucketsRequest request = new S3ListAllMyBucketsRequest();
|
||||
request.setAccessKey(listAllMyBuckets.getAWSAccessKeyId());
|
||||
request.setRequestTimestamp(listAllMyBuckets.getTimestamp());
|
||||
request.setSignature(listAllMyBuckets.getSignature());
|
||||
return request;
|
||||
}
|
||||
|
||||
public static ListAllMyBucketsResponse toListAllMyBucketsResponse(S3ListAllMyBucketsResponse engineResponse) {
|
||||
ListAllMyBucketsResponse response = new ListAllMyBucketsResponse();
|
||||
ListAllMyBucketsResult result = new ListAllMyBucketsResult();
|
||||
ListAllMyBucketsEntry[] entries = null;
|
||||
|
||||
S3CanonicalUser ownerEngine = engineResponse.getOwner();
|
||||
CanonicalUser owner = new CanonicalUser();
|
||||
owner.setID(ownerEngine.getID());
|
||||
owner.setDisplayName(ownerEngine.getDisplayName());
|
||||
result.setOwner(owner);
|
||||
S3ListAllMyBucketsEntry[] engineEntries = engineResponse.getBuckets();
|
||||
if (engineEntries != null) {
|
||||
entries = new ListAllMyBucketsEntry[engineEntries.length];
|
||||
for(int i = 0; i < engineEntries.length; i++) {
|
||||
entries[i] = new ListAllMyBucketsEntry();
|
||||
entries[i].setName(engineEntries[i].getName());
|
||||
entries[i].setCreationDate(engineEntries[i].getCreationDate()); //setTimeZone(TimeZone.getTimeZone("Z"));
|
||||
}
|
||||
|
||||
ListAllMyBucketsList list = new ListAllMyBucketsList();
|
||||
list.setBucket(entries);
|
||||
result.setBuckets(list);
|
||||
}
|
||||
response.setListAllMyBucketsResponse(result);
|
||||
return response;
|
||||
}
|
||||
|
||||
public DeleteBucketResponse deleteBucket(DeleteBucket deleteBucket) {
|
||||
return toDeleteBucketResponse(engine.handleRequest(toEngineDeleteBucketRequest(deleteBucket)));
|
||||
}
|
||||
|
||||
private S3DeleteBucketRequest toEngineDeleteBucketRequest(DeleteBucket deleteBucket) {
|
||||
S3DeleteBucketRequest request = new S3DeleteBucketRequest();
|
||||
request.setAccessKey(deleteBucket.getAWSAccessKeyId());
|
||||
request.setRequestTimestamp(deleteBucket.getTimestamp());
|
||||
request.setSignature(deleteBucket.getSignature());
|
||||
request.setBucketName(deleteBucket.getBucket());
|
||||
return request;
|
||||
}
|
||||
|
||||
private DeleteBucketResponse toDeleteBucketResponse(S3Response engineResponse) {
|
||||
DeleteBucketResponse response = new DeleteBucketResponse();
|
||||
Status status = new Status();
|
||||
status.setCode(engineResponse.getResultCode());
|
||||
status.setDescription(engineResponse.getResultDescription());
|
||||
response.setDeleteBucketResponse(status);
|
||||
return response;
|
||||
}
|
||||
|
||||
public GetObjectResponse getObject(com.amazon.s3.GetObject getObject) {
|
||||
return toGetObjectResponse(engine.handleRequest(toEngineGetObjectRequest(getObject)));
|
||||
}
|
||||
|
||||
public GetObjectExtendedResponse getObjectExtended(GetObjectExtended getObjectExtended) {
|
||||
return toGetObjectExtendedResponse(engine.handleRequest(toEngineGetObjectRequest(getObjectExtended)));
|
||||
}
|
||||
|
||||
private S3GetObjectRequest toEngineGetObjectRequest(GetObject getObject)
|
||||
{
|
||||
S3GetObjectRequest request = new S3GetObjectRequest();
|
||||
|
||||
request.setAccessKey(getObject.getAWSAccessKeyId());
|
||||
request.setRequestTimestamp(getObject.getTimestamp());
|
||||
request.setSignature(getObject.getSignature());
|
||||
request.setBucketName(getObject.getBucket());
|
||||
request.setKey(getObject.getKey());
|
||||
request.setReturnData(getObject.getGetData());
|
||||
request.setReturnMetadata(getObject.getGetMetadata());
|
||||
request.setInlineData(getObject.getInlineData());
|
||||
return request;
|
||||
}
|
||||
|
||||
private S3GetObjectRequest toEngineGetObjectRequest(GetObjectExtended getObjectExtended) {
|
||||
S3GetObjectRequest request = new S3GetObjectRequest();
|
||||
request.setAccessKey(getObjectExtended.getAWSAccessKeyId());
|
||||
request.setRequestTimestamp(getObjectExtended.getTimestamp());
|
||||
request.setSignature(getObjectExtended.getSignature());
|
||||
request.setBucketName(getObjectExtended.getBucket());
|
||||
request.setKey(getObjectExtended.getKey());
|
||||
request.setReturnData(getObjectExtended.getGetData());
|
||||
request.setReturnMetadata(getObjectExtended.getGetMetadata());
|
||||
request.setInlineData(getObjectExtended.getInlineData());
|
||||
|
||||
S3ConditionalHeaders conds = new S3ConditionalHeaders();
|
||||
conds.setModifiedSince(getObjectExtended.getIfModifiedSince());
|
||||
conds.setUnModifiedSince(getObjectExtended.getIfUnmodifiedSince());
|
||||
conds.setMatch(getObjectExtended.getIfMatch());
|
||||
conds.setNoneMatch(getObjectExtended.getIfNoneMatch());
|
||||
request.setConditions(conds);
|
||||
|
||||
request.setByteRangeStart(getObjectExtended.getByteRangeStart());
|
||||
request.setByteRangeEnd(getObjectExtended.getByteRangeEnd());
|
||||
request.setReturnCompleteObjectOnConditionFailure(getObjectExtended.getReturnCompleteObjectOnConditionFailure());
|
||||
return request;
|
||||
}
|
||||
|
||||
private GetObjectResponse toGetObjectResponse(S3GetObjectResponse engineResponse) {
|
||||
GetObjectResponse response = new GetObjectResponse();
|
||||
int resultCode = engineResponse.getResultCode();
|
||||
|
||||
GetObjectResult result = new GetObjectResult();
|
||||
Status param1 = new Status();
|
||||
param1.setCode( resultCode);
|
||||
param1.setDescription( engineResponse.getResultDescription());
|
||||
result.setStatus( param1 );
|
||||
|
||||
if ( 200 == resultCode )
|
||||
{
|
||||
result.setData(engineResponse.getData());
|
||||
result.setETag( engineResponse.getETag());
|
||||
result.setMetadata(toMetadataEntry(engineResponse.getMetaEntries()));
|
||||
result.setLastModified( engineResponse.getLastModified());
|
||||
}
|
||||
else
|
||||
{ result.setETag( "" );
|
||||
result.setLastModified( Calendar.getInstance());
|
||||
}
|
||||
|
||||
response.setGetObjectResponse(result);
|
||||
return response;
|
||||
}
|
||||
|
||||
private GetObjectExtendedResponse toGetObjectExtendedResponse(S3GetObjectResponse engineResponse) {
|
||||
GetObjectExtendedResponse response = new GetObjectExtendedResponse();
|
||||
int resultCode = engineResponse.getResultCode();
|
||||
|
||||
GetObjectResult result = new GetObjectResult();
|
||||
Status param1 = new Status();
|
||||
param1.setCode( resultCode );
|
||||
param1.setDescription( engineResponse.getResultDescription());
|
||||
result.setStatus( param1 );
|
||||
|
||||
if ( 200 == resultCode || 206 == resultCode )
|
||||
{
|
||||
result.setData(engineResponse.getData());
|
||||
result.setETag( engineResponse.getETag());
|
||||
result.setMetadata(toMetadataEntry(engineResponse.getMetaEntries()));
|
||||
result.setLastModified( engineResponse.getLastModified());
|
||||
}
|
||||
else
|
||||
{ result.setETag( "" );
|
||||
result.setLastModified( Calendar.getInstance());
|
||||
}
|
||||
|
||||
response.setGetObjectResponse(result);
|
||||
return response;
|
||||
}
|
||||
|
||||
private MetadataEntry[] toMetadataEntry(S3MetaDataEntry[] engineEntries) {
|
||||
if(engineEntries != null) {
|
||||
MetadataEntry[] entries = new MetadataEntry[engineEntries.length];
|
||||
for(int i = 0; i < engineEntries.length; i++) {
|
||||
entries[i] = new MetadataEntry();
|
||||
entries[i].setName(engineEntries[i].getName());
|
||||
entries[i].setValue(engineEntries[i].getValue());
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public GetObjectAccessControlPolicyResponse getObjectAccessControlPolicy(
|
||||
GetObjectAccessControlPolicy getObjectAccessControlPolicy) {
|
||||
return toGetObjectAccessControlPolicyResponse(engine.handleRequest(
|
||||
toEngineGetObjectAccessControlPolicyRequest(getObjectAccessControlPolicy)));
|
||||
}
|
||||
|
||||
private S3GetObjectAccessControlPolicyRequest toEngineGetObjectAccessControlPolicyRequest(
|
||||
GetObjectAccessControlPolicy getObjectAccessControlPolicy) {
|
||||
S3GetObjectAccessControlPolicyRequest request = new S3GetObjectAccessControlPolicyRequest();
|
||||
|
||||
request.setAccessKey(getObjectAccessControlPolicy.getAWSAccessKeyId());
|
||||
request.setRequestTimestamp(getObjectAccessControlPolicy.getTimestamp());
|
||||
request.setSignature(getObjectAccessControlPolicy.getSignature());
|
||||
request.setBucketName(getObjectAccessControlPolicy.getBucket());
|
||||
request.setKey(getObjectAccessControlPolicy.getKey());
|
||||
return request;
|
||||
}
|
||||
|
||||
public static GetObjectAccessControlPolicyResponse toGetObjectAccessControlPolicyResponse(S3AccessControlPolicy policy) {
|
||||
GetObjectAccessControlPolicyResponse response = new GetObjectAccessControlPolicyResponse();
|
||||
response.setGetObjectAccessControlPolicyResponse(toAccessControlPolicy(policy));
|
||||
return response;
|
||||
}
|
||||
|
||||
private static AccessControlPolicy toAccessControlPolicy(S3AccessControlPolicy enginePolicy) {
|
||||
AccessControlPolicy policy = new AccessControlPolicy();
|
||||
CanonicalUser owner = new CanonicalUser();
|
||||
owner.setID(enginePolicy.getOwner().getID());
|
||||
owner.setDisplayName(enginePolicy.getOwner().getDisplayName());
|
||||
policy.setOwner(owner);
|
||||
|
||||
AccessControlList acl = new AccessControlList();
|
||||
acl.setGrant(toGrants(enginePolicy.getGrants()));
|
||||
policy.setAccessControlList(acl);
|
||||
return policy;
|
||||
}
|
||||
|
||||
public DeleteObjectResponse deleteObject (DeleteObject deleteObject) {
|
||||
return toDeleteObjectResponse(engine.handleRequest(toEngineDeleteObjectRequest(deleteObject)));
|
||||
}
|
||||
|
||||
private S3DeleteObjectRequest toEngineDeleteObjectRequest(DeleteObject deleteObject) {
|
||||
S3DeleteObjectRequest request = new S3DeleteObjectRequest();
|
||||
request.setAccessKey(deleteObject.getAWSAccessKeyId());
|
||||
request.setRequestTimestamp(deleteObject.getTimestamp());
|
||||
request.setSignature(deleteObject.getSignature());
|
||||
request.setBucketName(deleteObject.getBucket());
|
||||
request.setKey(deleteObject.getKey());
|
||||
return request;
|
||||
}
|
||||
|
||||
private DeleteObjectResponse toDeleteObjectResponse(S3Response engineResponse) {
|
||||
DeleteObjectResponse response = new DeleteObjectResponse();
|
||||
Status status = new Status();
|
||||
status.setCode(engineResponse.getResultCode());
|
||||
status.setDescription(engineResponse.getResultDescription());
|
||||
response.setDeleteObjectResponse(status);
|
||||
return response;
|
||||
}
|
||||
|
||||
public SetObjectAccessControlPolicyResponse setObjectAccessControlPolicy(SetObjectAccessControlPolicy setObjectAccessControlPolicy)
|
||||
{
|
||||
S3SetObjectAccessControlPolicyRequest request = new S3SetObjectAccessControlPolicyRequest();
|
||||
request.setAccessKey(setObjectAccessControlPolicy.getAWSAccessKeyId());
|
||||
request.setRequestTimestamp(setObjectAccessControlPolicy.getTimestamp());
|
||||
request.setSignature(setObjectAccessControlPolicy.getSignature());
|
||||
request.setBucketName(setObjectAccessControlPolicy.getBucket());
|
||||
request.setKey(setObjectAccessControlPolicy.getKey());
|
||||
request.setAcl(toEngineAccessControlList(setObjectAccessControlPolicy.getAccessControlList()));
|
||||
|
||||
engine.handleRequest(request);
|
||||
SetObjectAccessControlPolicyResponse response = new SetObjectAccessControlPolicyResponse();
|
||||
return response;
|
||||
}
|
||||
|
||||
public PutObjectInlineResponse putObjectInline (PutObjectInline putObjectInline) {
|
||||
return toPutObjectInlineResponse(engine.handleRequest(toEnginePutObjectInlineRequest(putObjectInline)));
|
||||
}
|
||||
|
||||
private S3PutObjectInlineRequest toEnginePutObjectInlineRequest(PutObjectInline putObjectInline) {
|
||||
S3PutObjectInlineRequest request = new S3PutObjectInlineRequest();
|
||||
request.setAccessKey(putObjectInline.getAWSAccessKeyId());
|
||||
request.setRequestTimestamp(putObjectInline.getTimestamp());
|
||||
request.setSignature(putObjectInline.getSignature());
|
||||
request.setBucketName(putObjectInline.getBucket());
|
||||
request.setContentLength(putObjectInline.getContentLength());
|
||||
request.setKey(putObjectInline.getKey());
|
||||
request.setData(putObjectInline.getData());
|
||||
request.setMetaEntries(toEngineMetaEntries(putObjectInline.getMetadata()));
|
||||
request.setAcl(toEngineAccessControlList(putObjectInline.getAccessControlList()));
|
||||
return request;
|
||||
}
|
||||
|
||||
private S3MetaDataEntry[] toEngineMetaEntries(MetadataEntry[] metaEntries) {
|
||||
if(metaEntries != null) {
|
||||
S3MetaDataEntry[] engineMetaEntries = new S3MetaDataEntry[metaEntries.length];
|
||||
for(int i = 0; i < metaEntries.length; i++) {
|
||||
engineMetaEntries[i] = new S3MetaDataEntry();
|
||||
engineMetaEntries[i].setName(metaEntries[i].getName());
|
||||
engineMetaEntries[i].setValue(metaEntries[i].getValue());
|
||||
}
|
||||
return engineMetaEntries;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private S3AccessControlList toEngineAccessControlList(AccessControlList acl)
|
||||
{
|
||||
if (acl == null) return null;
|
||||
|
||||
S3AccessControlList engineAcl = new S3AccessControlList();
|
||||
|
||||
Grant[] grants = acl.getGrant();
|
||||
if (grants != null)
|
||||
{
|
||||
for (Grant grant: grants)
|
||||
{
|
||||
S3Grant engineGrant = new S3Grant();
|
||||
|
||||
Grantee grantee = grant.getGrantee();
|
||||
if (grantee instanceof CanonicalUser)
|
||||
{
|
||||
engineGrant.setGrantee(SAcl.GRANTEE_USER);
|
||||
engineGrant.setCanonicalUserID(((CanonicalUser)grantee).getID());
|
||||
}
|
||||
else if (grantee instanceof Group)
|
||||
{
|
||||
Group temp = (Group)grantee;
|
||||
String uri = temp.getURI();
|
||||
if ( uri.equalsIgnoreCase( "http://acs.amazonaws.com/groups/global/AllUsers" )) {
|
||||
// -> this allows all public unauthenticated access based on permission given
|
||||
engineGrant.setGrantee(SAcl.GRANTEE_ALLUSERS);
|
||||
engineGrant.setCanonicalUserID( "*" );
|
||||
}
|
||||
else if (uri.equalsIgnoreCase( "http://acs.amazonaws.com/groups/global/Authenticated" )) {
|
||||
// -> this allows any authenticated user access based on permission given
|
||||
engineGrant.setGrantee(SAcl.GRANTEE_AUTHENTICATED);
|
||||
engineGrant.setCanonicalUserID( "A" );
|
||||
}
|
||||
else throw new UnsupportedOperationException("Unsupported grantee group URI: " + uri );
|
||||
|
||||
}
|
||||
else throw new UnsupportedOperationException("Unsupported grantee type: " + grantee.getClass().getCanonicalName());
|
||||
|
||||
Permission permission = grant.getPermission();
|
||||
String permissionValue = permission.getValue();
|
||||
if(permissionValue.equalsIgnoreCase("READ")) {
|
||||
engineGrant.setPermission(SAcl.PERMISSION_READ);
|
||||
} else if(permissionValue.equalsIgnoreCase("WRITE")) {
|
||||
engineGrant.setPermission(SAcl.PERMISSION_WRITE);
|
||||
} else if(permissionValue.equalsIgnoreCase("READ_ACP")) {
|
||||
engineGrant.setPermission(SAcl.PERMISSION_READ_ACL);
|
||||
} else if(permissionValue.equalsIgnoreCase("WRITE_ACP")) {
|
||||
engineGrant.setPermission(SAcl.PERMISSION_WRITE_ACL);
|
||||
} else if(permissionValue.equalsIgnoreCase("FULL_CONTROL")) {
|
||||
engineGrant.setPermission(SAcl.PERMISSION_FULL);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unsupported permission: " + permissionValue);
|
||||
}
|
||||
engineAcl.addGrant(engineGrant);
|
||||
}
|
||||
}
|
||||
return engineAcl;
|
||||
}
|
||||
|
||||
private static Grant[] toGrants(S3Grant[] engineGrants) {
|
||||
Grantee grantee = null;
|
||||
Grant[] grants = null;
|
||||
|
||||
if (engineGrants != null && 0 < engineGrants.length)
|
||||
{
|
||||
grants = new Grant[engineGrants.length];
|
||||
for(int i = 0; i < engineGrants.length; i++)
|
||||
{
|
||||
grants[i] = new Grant();
|
||||
|
||||
switch( engineGrants[i].getGrantee()) {
|
||||
case SAcl.GRANTEE_USER :
|
||||
grantee = new CanonicalUser();
|
||||
((CanonicalUser)grantee).setID(engineGrants[i].getCanonicalUserID());
|
||||
((CanonicalUser)grantee).setDisplayName("TODO");
|
||||
grants[i].setGrantee(grantee);
|
||||
break;
|
||||
|
||||
case SAcl.GRANTEE_ALLUSERS:
|
||||
grantee = new Group();
|
||||
((Group)grantee).setURI( "http://acs.amazonaws.com/groups/global/AllUsers" );
|
||||
grants[i].setGrantee(grantee);
|
||||
break;
|
||||
|
||||
case SAcl.GRANTEE_AUTHENTICATED:
|
||||
grantee = new Group();
|
||||
((Group)grantee).setURI( "http://acs.amazonaws.com/groups/global/Authenticated" );
|
||||
grants[i].setGrantee(grantee);
|
||||
break;
|
||||
|
||||
default :
|
||||
throw new InternalErrorException("Unsupported grantee type");
|
||||
}
|
||||
|
||||
|
||||
switch( engineGrants[i].getPermission()) {
|
||||
case SAcl.PERMISSION_READ: grants[i].setPermission(Permission.READ); break;
|
||||
case SAcl.PERMISSION_WRITE: grants[i].setPermission(Permission.WRITE); break;
|
||||
case SAcl.PERMISSION_READ_ACL: grants[i].setPermission(Permission.READ_ACP); break;
|
||||
case SAcl.PERMISSION_WRITE_ACL: grants[i].setPermission(Permission.WRITE_ACP); break;
|
||||
case SAcl.PERMISSION_FULL: grants[i].setPermission(Permission.FULL_CONTROL); break;
|
||||
}
|
||||
}
|
||||
return grants;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private PutObjectInlineResponse toPutObjectInlineResponse(S3PutObjectInlineResponse engineResponse) {
|
||||
PutObjectInlineResponse response = new PutObjectInlineResponse();
|
||||
|
||||
PutObjectResult result = new PutObjectResult();
|
||||
result.setETag(engineResponse.getETag());
|
||||
result.setLastModified(engineResponse.getLastModified());
|
||||
response.setPutObjectInlineResponse(result);
|
||||
return response;
|
||||
}
|
||||
|
||||
public static CopyObjectResponse toCopyObjectResponse(S3CopyObjectResponse engineResponse) throws AxisFault {
|
||||
CopyObjectResponse response = new CopyObjectResponse();
|
||||
int resultCode = engineResponse.getResultCode();
|
||||
|
||||
CopyObjectResult result = new CopyObjectResult();
|
||||
if ( 300 <= resultCode )
|
||||
{
|
||||
String description = engineResponse.getResultDescription();
|
||||
throw new AxisFault( "" + resultCode, (null == description ? "" : description));
|
||||
}
|
||||
|
||||
result.setETag( "\"" + engineResponse.getETag() + "\"" );
|
||||
result.setLastModified(engineResponse.getLastModified());
|
||||
response.setCopyObjectResult(result);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,358 @@
|
|||
/**
|
||||
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved
|
||||
*
|
||||
* This software is licensed under the GNU General Public License v3 or later.
|
||||
*
|
||||
* It is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or any later version.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.cloud.bridge.service.controller.s3;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.net.InetAddress;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import org.apache.axis2.AxisFault;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.xml.DOMConfigurator;
|
||||
import org.hibernate.SessionException;
|
||||
|
||||
import com.amazon.s3.AmazonS3SkeletonInterface;
|
||||
import com.amazon.ec2.AmazonEC2SkeletonInterface;
|
||||
import com.cloud.bridge.model.MHost;
|
||||
import com.cloud.bridge.model.SHost;
|
||||
import com.cloud.bridge.model.UserCredentials;
|
||||
import com.cloud.bridge.persist.PersistContext;
|
||||
import com.cloud.bridge.persist.PersistException;
|
||||
import com.cloud.bridge.persist.dao.MHostDao;
|
||||
import com.cloud.bridge.persist.dao.SHostDao;
|
||||
import com.cloud.bridge.persist.dao.UserCredentialsDao;
|
||||
import com.cloud.bridge.service.EC2SoapServiceImpl;
|
||||
import com.cloud.bridge.service.UserInfo;
|
||||
import com.cloud.bridge.service.core.ec2.EC2Engine;
|
||||
import com.cloud.bridge.service.core.s3.S3BucketPolicy;
|
||||
import com.cloud.bridge.service.core.s3.S3Engine;
|
||||
import com.cloud.bridge.service.exception.ConfigurationException;
|
||||
import com.cloud.bridge.util.ConfigurationHelper;
|
||||
import com.cloud.bridge.util.DateHelper;
|
||||
import com.cloud.bridge.util.NetHelper;
|
||||
import com.cloud.bridge.util.OrderedPair;
|
||||
|
||||
/**
|
||||
* @author Kelven Yang
|
||||
*/
|
||||
public class ServiceProvider {
|
||||
protected final static Logger logger = Logger.getLogger(ServiceProvider.class);
|
||||
|
||||
public final static long HEARTBEAT_INTERVAL = 10000;
|
||||
|
||||
private static ServiceProvider instance;
|
||||
|
||||
private Map<Class<?>, Object> serviceMap = new HashMap<Class<?>, Object>();
|
||||
private Timer timer = new Timer();
|
||||
private MHost mhost;
|
||||
private Properties properties;
|
||||
private boolean useSubDomain = false; // use DNS sub domain for bucket name
|
||||
private String serviceEndpoint = null;
|
||||
private String multipartDir = null; // illegal bucket name used as a folder for storing multiparts
|
||||
private String masterDomain = ".s3.amazonaws.com";
|
||||
private S3Engine engine;
|
||||
private EC2Engine EC2_engine = null;
|
||||
|
||||
// -> cache Bucket Policies here so we don't have to load from db on every access
|
||||
private Map<String,S3BucketPolicy> policyMap = new HashMap<String,S3BucketPolicy>();
|
||||
|
||||
protected ServiceProvider() throws IOException {
|
||||
// register service implementation object
|
||||
engine = new S3Engine();
|
||||
EC2_engine = new EC2Engine();
|
||||
serviceMap.put(AmazonS3SkeletonInterface.class, new S3SerializableServiceImplementation(engine));
|
||||
serviceMap.put(AmazonEC2SkeletonInterface.class, new EC2SoapServiceImpl(EC2_engine));
|
||||
}
|
||||
|
||||
public synchronized static ServiceProvider getInstance() {
|
||||
if(instance == null)
|
||||
{
|
||||
try {
|
||||
instance = new ServiceProvider();
|
||||
instance.initialize();
|
||||
PersistContext.commitTransaction();
|
||||
} catch(Throwable e) {
|
||||
logger.error("Unexpected exception " + e.getMessage(), e);
|
||||
} finally {
|
||||
PersistContext.closeSession();
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public long getManagementHostId() {
|
||||
// we want to limit mhost within its own session, id of the value will be returned
|
||||
long mhostId = 0;
|
||||
if(mhost != null)
|
||||
mhostId = mhost.getId() != null ? mhost.getId().longValue() : 0L;
|
||||
return mhostId;
|
||||
}
|
||||
|
||||
/**
|
||||
* We return a 2-tuple to distinguish between two cases:
|
||||
* (1) there is no entry in the map for bucketName, and (2) there is a null entry
|
||||
* in the map for bucketName. In case 2, the database was inspected for the
|
||||
* bucket policy but it had none so we cache it here to reduce database lookups.
|
||||
* @param bucketName
|
||||
* @return Integer in the tuple means: -1 if no policy defined for the bucket, 0 if one defined
|
||||
* even if it is set at null.
|
||||
*/
|
||||
public OrderedPair<S3BucketPolicy,Integer> getBucketPolicy(String bucketName) {
|
||||
|
||||
if (policyMap.containsKey( bucketName )) {
|
||||
S3BucketPolicy policy = policyMap.get( bucketName );
|
||||
return new OrderedPair<S3BucketPolicy,Integer>( policy, 0 );
|
||||
}
|
||||
else return new OrderedPair<S3BucketPolicy,Integer>( null, -1 ); // For case (1) where the map has no entry for bucketName
|
||||
}
|
||||
|
||||
/**
|
||||
* The policy parameter can be set to null, which means that there is no policy
|
||||
* for the bucket so a database lookup is not necessary.
|
||||
*
|
||||
* @param bucketName
|
||||
* @param policy
|
||||
*/
|
||||
public void setBucketPolicy(String bucketName, S3BucketPolicy policy) {
|
||||
policyMap.put(bucketName, policy);
|
||||
}
|
||||
|
||||
public void deleteBucketPolicy(String bucketName) {
|
||||
policyMap.remove(bucketName);
|
||||
}
|
||||
|
||||
public S3Engine getS3Engine() {
|
||||
return engine;
|
||||
}
|
||||
|
||||
public EC2Engine getEC2Engine() {
|
||||
return EC2_engine;
|
||||
}
|
||||
|
||||
public String getMasterDomain() {
|
||||
return masterDomain;
|
||||
}
|
||||
|
||||
public boolean getUseSubDomain() {
|
||||
return useSubDomain;
|
||||
}
|
||||
|
||||
public String getServiceEndpoint() {
|
||||
return serviceEndpoint;
|
||||
}
|
||||
|
||||
public String getMultipartDir() {
|
||||
return multipartDir;
|
||||
}
|
||||
|
||||
public Properties getStartupProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public UserInfo getUserInfo(String accessKey)
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException {
|
||||
UserInfo info = new UserInfo();
|
||||
|
||||
UserCredentialsDao credentialDao = new UserCredentialsDao();
|
||||
UserCredentials cloudKeys = credentialDao.getByAccessKey( accessKey );
|
||||
if ( null == cloudKeys ) {
|
||||
logger.debug( accessKey + " is not defined in the S3 service - call SetUserKeys" );
|
||||
return null;
|
||||
} else {
|
||||
info.setAccessKey( accessKey );
|
||||
info.setSecretKey( cloudKeys.getSecretKey());
|
||||
info.setCanonicalUserId(accessKey);
|
||||
info.setDescription( "S3 REST request" );
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
protected void initialize() {
|
||||
if(logger.isInfoEnabled())
|
||||
logger.info("Initializing ServiceProvider...");
|
||||
|
||||
File file = ConfigurationHelper.findConfigurationFile("log4j-cloud-bridge.xml");
|
||||
if(file != null) {
|
||||
System.out.println("Log4j configuration from : " + file.getAbsolutePath());
|
||||
DOMConfigurator.configureAndWatch(file.getAbsolutePath(), 10000);
|
||||
} else {
|
||||
System.out.println("Configure log4j with default properties");
|
||||
}
|
||||
|
||||
loadStartupProperties();
|
||||
String hostKey = properties.getProperty("host.key");
|
||||
if(hostKey == null) {
|
||||
InetAddress inetAddr = NetHelper.getFirstNonLoopbackLocalInetAddress();
|
||||
if(inetAddr != null)
|
||||
hostKey = NetHelper.getMacAddress(inetAddr);
|
||||
}
|
||||
if(hostKey == null)
|
||||
throw new ConfigurationException("Please configure host.key property in cloud-bridge.properites");
|
||||
String host = properties.getProperty("host");
|
||||
if(host == null)
|
||||
host = NetHelper.getHostName();
|
||||
|
||||
if(properties.get("bucket.dns") != null &&
|
||||
((String)properties.get("bucket.dns")).equalsIgnoreCase("true")) {
|
||||
useSubDomain = true;
|
||||
}
|
||||
|
||||
serviceEndpoint = (String)properties.get("serviceEndpoint");
|
||||
masterDomain = new String( "." + serviceEndpoint );
|
||||
|
||||
setupHost(hostKey, host);
|
||||
|
||||
// we will commit and start a new transaction to allow host info be flushed to DB
|
||||
PersistContext.flush();
|
||||
|
||||
String localStorageRoot = properties.getProperty("storage.root");
|
||||
if (localStorageRoot != null) setupLocalStorage(localStorageRoot);
|
||||
|
||||
multipartDir = properties.getProperty("storage.multipartDir");
|
||||
|
||||
timer.schedule(getHeartbeatTask(), HEARTBEAT_INTERVAL, HEARTBEAT_INTERVAL);
|
||||
|
||||
if(logger.isInfoEnabled())
|
||||
logger.info("ServiceProvider initialized");
|
||||
}
|
||||
|
||||
private void loadStartupProperties() {
|
||||
File propertiesFile = ConfigurationHelper.findConfigurationFile("cloud-bridge.properties");
|
||||
properties = new Properties();
|
||||
if(propertiesFile != null) {
|
||||
try {
|
||||
properties.load(new FileInputStream(propertiesFile));
|
||||
} catch (FileNotFoundException e) {
|
||||
logger.warn("Unable to open properties file: " + propertiesFile.getAbsolutePath(), e);
|
||||
} catch (IOException e) {
|
||||
logger.warn("Unable to read properties file: " + propertiesFile.getAbsolutePath(), e);
|
||||
}
|
||||
|
||||
logger.info("Use startup properties file: " + propertiesFile.getAbsolutePath());
|
||||
} else {
|
||||
if(logger.isInfoEnabled())
|
||||
logger.info("Startup properties is not found.");
|
||||
}
|
||||
}
|
||||
|
||||
private TimerTask getHeartbeatTask() {
|
||||
return new TimerTask() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
MHostDao mhostDao = new MHostDao();
|
||||
mhost.setLastHeartbeatTime(DateHelper.currentGMTTime());
|
||||
mhostDao.update(mhost);
|
||||
PersistContext.commitTransaction();
|
||||
} catch(Throwable e){
|
||||
logger.error("Unexpected exception " + e.getMessage(), e);
|
||||
} finally {
|
||||
PersistContext.closeSession();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void setupHost(String hostKey, String host) {
|
||||
MHostDao mhostDao = new MHostDao();
|
||||
mhost = mhostDao.getByHostKey(hostKey);
|
||||
if(mhost == null) {
|
||||
mhost = new MHost();
|
||||
mhost.setHostKey(hostKey);
|
||||
mhost.setHost(host);
|
||||
mhost.setLastHeartbeatTime(DateHelper.currentGMTTime());
|
||||
mhostDao.save(mhost);
|
||||
} else {
|
||||
mhost.setHost(host);
|
||||
mhostDao.update(mhost);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupLocalStorage(String storageRoot) {
|
||||
SHostDao shostDao = new SHostDao();
|
||||
SHost shost = shostDao.getLocalStorageHost(mhost.getId(), storageRoot);
|
||||
if(shost == null) {
|
||||
shost = new SHost();
|
||||
shost.setMhost(mhost);
|
||||
mhost.getLocalSHosts().add(shost);
|
||||
shost.setHostType(SHost.STORAGE_HOST_TYPE_LOCAL);
|
||||
shost.setHost(NetHelper.getHostName());
|
||||
shost.setExportRoot(storageRoot);
|
||||
PersistContext.getSession().save(shost);
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
timer.cancel();
|
||||
|
||||
if(logger.isInfoEnabled())
|
||||
logger.info("ServiceProvider stopped");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T getProxy(Class<?> serviceInterface, final T serviceObject) {
|
||||
return (T) Proxy.newProxyInstance(serviceObject.getClass().getClassLoader(),
|
||||
new Class[] { serviceInterface },
|
||||
new InvocationHandler() {
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
Object result = null;
|
||||
try {
|
||||
result = method.invoke(serviceObject, args);
|
||||
PersistContext.commitTransaction();
|
||||
} catch (PersistException e) {
|
||||
} catch (SessionException e) {
|
||||
} catch(Throwable e) {
|
||||
// Rethrow the exception to Axis:
|
||||
// Check if the exception is an AxisFault or a RuntimeException
|
||||
// enveloped AxisFault and if so, pass it on as such. Otherwise
|
||||
// log to help debugging and throw as is.
|
||||
if (e.getCause() != null && e.getCause() instanceof AxisFault)
|
||||
throw e.getCause();
|
||||
else if (e.getCause() != null && e.getCause().getCause() != null
|
||||
&& e.getCause().getCause() instanceof AxisFault)
|
||||
throw e.getCause().getCause();
|
||||
else {
|
||||
logger.warn("Unhandled exception " + e.getMessage(), e);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
PersistContext.closeSession();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getServiceImpl(Class<?> serviceInterface) {
|
||||
return getProxy(serviceInterface, (T)serviceMap.get(serviceInterface));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.cloud.bridge.service.controller.s3;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
|
||||
/**
|
||||
* @author Kelven Yang
|
||||
*/
|
||||
public interface ServletAction {
|
||||
void execute(HttpServletRequest request, HttpServletResponse response) throws IOException, XMLStreamException;
|
||||
}
|
||||
|
|
@ -28,12 +28,17 @@ import java.util.List;
|
|||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
|
||||
<<<<<<< HEAD
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.cloud.bridge.persist.dao.CloudStackSvcOfferingDao;
|
||||
=======
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
import com.cloud.bridge.persist.dao.OfferingDao;
|
||||
import com.cloud.bridge.service.UserContext;
|
||||
import com.cloud.bridge.service.exception.EC2ServiceException;
|
||||
|
|
@ -56,7 +61,10 @@ import com.cloud.stack.models.CloudStackPasswordData;
|
|||
import com.cloud.stack.models.CloudStackResourceLimit;
|
||||
import com.cloud.stack.models.CloudStackSecurityGroup;
|
||||
import com.cloud.stack.models.CloudStackSecurityGroupIngress;
|
||||
<<<<<<< HEAD
|
||||
import com.cloud.stack.models.CloudStackServiceOffering;
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
import com.cloud.stack.models.CloudStackSnapshot;
|
||||
import com.cloud.stack.models.CloudStackTemplate;
|
||||
import com.cloud.stack.models.CloudStackUser;
|
||||
|
|
@ -508,9 +516,14 @@ public class EC2Engine {
|
|||
try {
|
||||
|
||||
CloudStackInfoResponse resp = getApi().deleteSnapshot(snapshotId);
|
||||
<<<<<<< HEAD
|
||||
if(resp != null) {
|
||||
return resp.getSuccess();
|
||||
}
|
||||
=======
|
||||
if(resp.getJobId() != null)
|
||||
return true;
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
return false;
|
||||
} catch(Exception e) {
|
||||
|
|
@ -943,10 +956,13 @@ public class EC2Engine {
|
|||
if (resp == null || resp.getId() == null) {
|
||||
throw new EC2ServiceException(ServerError.InternalError, "An upexpected error occurred.");
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
|
||||
//if template was created succesfully, create the new image response
|
||||
response = new EC2CreateImageResponse();
|
||||
response.setId(resp.getId());
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
// [C] If we stopped the virtual machine now we need to restart it
|
||||
if (needsRestart) {
|
||||
|
|
@ -977,8 +993,13 @@ public class EC2Engine {
|
|||
throw new EC2ServiceException(ServerError.InternalError, "Missing parameter - location/architecture/name");
|
||||
|
||||
List<CloudStackTemplate> templates = getApi().registerTemplate((request.getDescription() == null ? request.getName() : request.getDescription()),
|
||||
<<<<<<< HEAD
|
||||
request.getFormat(), request.getHypervisor(), request.getName(), toOSTypeId(request.getOsTypeName()), request.getLocation(),
|
||||
toZoneId(request.getZoneName(), null), null, null, null, null, null, null, null, null, null);
|
||||
=======
|
||||
request.getFormat(), null, request.getName(), toOSTypeId(request.getOsTypeName()), request.getLocation(),
|
||||
toZoneId(request.getZoneName(), caller.getDomainId()), null, null, null, null, null, null, null, null, null);
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
if (templates != null) {
|
||||
// technically we will only ever register a single template...
|
||||
for (CloudStackTemplate template : templates) {
|
||||
|
|
@ -1040,7 +1061,11 @@ public class EC2Engine {
|
|||
try {
|
||||
CloudStackAccount caller = getCurrentAccount();
|
||||
|
||||
<<<<<<< HEAD
|
||||
return listZones(request.getZoneSet(), null);
|
||||
=======
|
||||
return listZones(request.getZoneSet(), caller.getDomainId());
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
} catch( EC2ServiceException error ) {
|
||||
logger.error( "EC2 DescribeAvailabilityZones - ", error);
|
||||
|
|
@ -1088,7 +1113,11 @@ public class EC2Engine {
|
|||
*/
|
||||
public EC2Volume attachVolume( EC2Volume request ) {
|
||||
try {
|
||||
<<<<<<< HEAD
|
||||
request.setDeviceId(mapDeviceToCloudDeviceId(request.getDevice()));
|
||||
=======
|
||||
request.setDeviceId( mapDeviceToCloudDeviceId(request.getDevice()));
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
EC2Volume resp = new EC2Volume();
|
||||
|
||||
CloudStackVolume vol = getApi().attachVolume(request.getId(), request.getInstanceId(), request.getDeviceId());
|
||||
|
|
@ -1176,7 +1205,11 @@ public class EC2Engine {
|
|||
}
|
||||
|
||||
// // -> no volume name is given in the Amazon request but is required in the cloud API
|
||||
<<<<<<< HEAD
|
||||
CloudStackVolume vol = getApi().createVolume(UUID.randomUUID().toString(), null, diskOfferingId, null, size, snapshotId, toZoneId(request.getZoneName(), null));
|
||||
=======
|
||||
CloudStackVolume vol = getApi().createVolume(UUID.randomUUID().toString(), null, diskOfferingId, null, size, snapshotId, toZoneId(request.getZoneName(), caller.getDomainId()));
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
if (vol != null) {
|
||||
EC2Volume resp = new EC2Volume();
|
||||
resp.setAttached(vol.getAttached());
|
||||
|
|
@ -1287,6 +1320,7 @@ public class EC2Engine {
|
|||
else
|
||||
createInstances = request.getMaxCount();
|
||||
|
||||
<<<<<<< HEAD
|
||||
//find CS service Offering ID
|
||||
String instanceType = "m1.small";
|
||||
if(request.getInstanceType() != null){
|
||||
|
|
@ -1300,6 +1334,13 @@ public class EC2Engine {
|
|||
|
||||
// zone stuff
|
||||
String zoneId = toZoneId(request.getZoneName(), null);
|
||||
=======
|
||||
// the mapping stuff
|
||||
OfferingBundle offer = instanceTypeToOfferBundle( request.getInstanceType());
|
||||
|
||||
// zone stuff
|
||||
String zoneId = toZoneId(request.getZoneName(), caller.getDomainId());
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
List<CloudStackZone> zones = getApi().listZones(null, null, zoneId, null);
|
||||
if (zones == null || zones.size() == 0) {
|
||||
|
|
@ -1314,7 +1355,11 @@ public class EC2Engine {
|
|||
|
||||
// now actually deploy the vms
|
||||
for( int i=0; i < createInstances; i++ ) {
|
||||
<<<<<<< HEAD
|
||||
CloudStackUserVm resp = getApi().deployVirtualMachine(svcOffering.getId(),
|
||||
=======
|
||||
CloudStackUserVm resp = getApi().deployVirtualMachine(offer.getServiceOfferingId(),
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
request.getTemplateId(), zoneId, null, null, null, null,
|
||||
null, null, null, request.getKeyName(), null, (network != null ? network.getId() : null),
|
||||
null, null, request.getSize().longValue(), request.getUserData());
|
||||
|
|
@ -1334,7 +1379,11 @@ public class EC2Engine {
|
|||
vm.setAccountName(resp.getAccountName());
|
||||
vm.setDomainId(resp.getDomainId());
|
||||
vm.setHypervisor(resp.getHypervisor());
|
||||
<<<<<<< HEAD
|
||||
vm.setServiceOffering( svcOffering.getName());
|
||||
=======
|
||||
vm.setServiceOffering( serviceOfferingIdToInstanceType( offer.getServiceOfferingId()));
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
instances.addInstance(vm);
|
||||
countCreated++;
|
||||
}
|
||||
|
|
@ -1374,11 +1423,17 @@ public class EC2Engine {
|
|||
if (vm.getState().equalsIgnoreCase( "Running" ) || vm.getState().equalsIgnoreCase( "Destroyed" )) continue;
|
||||
|
||||
CloudStackUserVm resp = getApi().startVirtualMachine(vm.getId());
|
||||
<<<<<<< HEAD
|
||||
if(resp != null){
|
||||
vm.setState(resp.getState());
|
||||
if(logger.isDebugEnabled())
|
||||
logger.debug("Starting VM " + vm.getId() + " job " + resp.getJobId());
|
||||
}
|
||||
=======
|
||||
|
||||
if(logger.isDebugEnabled())
|
||||
logger.debug("Starting VM " + vm.getId() + " job " + resp.getJobId());
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
instances.addInstance(vm);
|
||||
}
|
||||
return instances;
|
||||
|
|
@ -1420,10 +1475,14 @@ public class EC2Engine {
|
|||
if(logger.isDebugEnabled())
|
||||
logger.debug("Stopping VM " + vm.getId() + " job " + resp.getJobId());
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
if (resp != null) {
|
||||
vm.setState(resp.getState());
|
||||
instances.addInstance(vm);
|
||||
}
|
||||
=======
|
||||
if (resp != null) instances.addInstance(vm);
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
return instances;
|
||||
} catch( Exception e ) {
|
||||
|
|
@ -1559,6 +1618,7 @@ public class EC2Engine {
|
|||
return zones.getZoneIdAt(0);
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
|
||||
/**
|
||||
* Convert from the Amazon instanceType strings to Cloud serviceOfferingId
|
||||
|
|
@ -1578,6 +1638,35 @@ public class EC2Engine {
|
|||
}
|
||||
}
|
||||
|
||||
=======
|
||||
/**
|
||||
* Convert from the Amazon instanceType strings to the Cloud APIs diskOfferingId and
|
||||
* serviceOfferingId based on the loaded map.
|
||||
*
|
||||
* @param instanceType - if null we return the M1Small instance type
|
||||
*
|
||||
* @return an OfferingBundle
|
||||
* @throws SQLException, ClassNotFoundException, IllegalAccessException, InstantiationException
|
||||
*/
|
||||
private OfferingBundle instanceTypeToOfferBundle( String instanceType )
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException {
|
||||
OfferingBundle found = null;
|
||||
OfferingDao ofDao = new OfferingDao();
|
||||
|
||||
if (null == instanceType) instanceType = "m1.small";
|
||||
String cloudOffering = ofDao.getCloudOffering( instanceType );
|
||||
|
||||
if ( null != cloudOffering )
|
||||
{
|
||||
found = new OfferingBundle();
|
||||
found.setServiceOfferingId( cloudOffering );
|
||||
}
|
||||
else throw new EC2ServiceException( ClientError.Unsupported, "Unknown: " + instanceType );
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
/**
|
||||
* Convert from the Cloud serviceOfferingId to the Amazon instanceType strings based
|
||||
* on the loaded map.
|
||||
|
|
@ -1586,6 +1675,7 @@ public class EC2Engine {
|
|||
* @return A valid value for the Amazon defined instanceType
|
||||
* @throws SQLException, ClassNotFoundException, IllegalAccessException, InstantiationException
|
||||
*/
|
||||
<<<<<<< HEAD
|
||||
private String serviceOfferingIdToInstanceType( String serviceOfferingId ){
|
||||
try{
|
||||
CloudStackSvcOfferingDao dao = new CloudStackSvcOfferingDao();
|
||||
|
|
@ -1600,6 +1690,18 @@ public class EC2Engine {
|
|||
logger.error( "sError while retrieving ServiceOffering information by id - ", e);
|
||||
throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
|
||||
}
|
||||
=======
|
||||
private String serviceOfferingIdToInstanceType( String serviceOfferingId )
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException {
|
||||
OfferingDao ofDao = new OfferingDao();
|
||||
String amazonOffering = ofDao.getAmazonOffering( serviceOfferingId.trim());
|
||||
|
||||
if ( null == amazonOffering ) {
|
||||
logger.warn( "No instanceType match for serverOfferingId: [" + serviceOfferingId + "]" );
|
||||
return "m1.small";
|
||||
}
|
||||
else return amazonOffering;
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1718,6 +1820,7 @@ public class EC2Engine {
|
|||
*/
|
||||
private EC2DescribeImagesResponse listTemplates( String templateId, EC2DescribeImagesResponse images ) throws EC2ServiceException {
|
||||
try {
|
||||
<<<<<<< HEAD
|
||||
List<CloudStackTemplate> result = new ArrayList<CloudStackTemplate>();
|
||||
|
||||
if(templateId != null){
|
||||
|
|
@ -1749,6 +1852,11 @@ public class EC2Engine {
|
|||
|
||||
if (result != null && result.size() > 0) {
|
||||
for (CloudStackTemplate temp : result) {
|
||||
=======
|
||||
List<CloudStackTemplate> resp = getApi().listTemplates("executable", null, null, null, templateId != null ? templateId : null, null, null, null);
|
||||
if (resp != null && resp.size() > 0) {
|
||||
for (CloudStackTemplate temp : resp) {
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
EC2Image ec2Image = new EC2Image();
|
||||
ec2Image.setId(temp.getId().toString());
|
||||
ec2Image.setAccountName(temp.getAccount());
|
||||
|
|
@ -1859,7 +1967,11 @@ public class EC2Engine {
|
|||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
<<<<<<< HEAD
|
||||
public CloudStackAccount getCurrentAccount() throws Exception {
|
||||
=======
|
||||
private CloudStackAccount getCurrentAccount() throws Exception {
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
if (currentAccount != null) {
|
||||
// verify this is the same account!!!
|
||||
for (CloudStackUser user : currentAccount.getUser()) {
|
||||
|
|
@ -1911,9 +2023,15 @@ public class EC2Engine {
|
|||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
<<<<<<< HEAD
|
||||
private CloudStackNetwork createDefaultGuestNetwork(String zoneId, CloudStackNetworkOffering offering, CloudStackAccount owner) throws Exception {
|
||||
return getApi().createNetwork(owner.getName() + "-network", owner.getName() + "-network", offering.getId(), zoneId, owner.getName(),
|
||||
owner.getDomainId(), true, null, null, null, null, null, null, null, null);
|
||||
=======
|
||||
private CloudStackNetwork createNetwork(String zoneId, CloudStackNetworkOffering offering, CloudStackAccount owner) throws Exception {
|
||||
return getApi().createNetwork(owner.getName() + "-network", owner.getName() + "-network", offering.getId(), zoneId, owner.getName(),
|
||||
null, null, null, null, null, null, null, null, null, null);
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1926,6 +2044,7 @@ public class EC2Engine {
|
|||
private CloudStackNetwork getNetworksWithoutSecurityGroupEnabled(String zoneId) throws Exception {
|
||||
// grab current account
|
||||
CloudStackAccount caller = getCurrentAccount();
|
||||
<<<<<<< HEAD
|
||||
|
||||
//check if account has any networks in the system
|
||||
List<CloudStackNetwork> networks = getApi().listNetworks(caller.getName(), caller.getDomainId(), null, true, null, null, null, null, null, zoneId);
|
||||
|
|
@ -1964,6 +2083,31 @@ public class EC2Engine {
|
|||
}
|
||||
}
|
||||
|
||||
=======
|
||||
|
||||
List<CloudStackNetwork> networks = getApi().listNetworks(null, caller.getDomainId(), null, null, null, null, null, null, null, zoneId);
|
||||
|
||||
List<CloudStackNetworkOffering> offerings = getApi().listNetworkOfferings("Required", null, null, null, true, null, null, null, null, null, zoneId);
|
||||
if (offerings != null && !offerings.isEmpty()) {
|
||||
for (CloudStackNetwork network : networks)
|
||||
for (CloudStackNetworkOffering offering : offerings) {
|
||||
logger.debug("[reqd/virtual} offering: " + offering.getId() + " network " + network.getNetworkOfferingId());
|
||||
if (network.getNetworkOfferingId().equals(offering.getId()))
|
||||
return network;
|
||||
}
|
||||
// if we get this far, we didn't find a network, so create one and return it.
|
||||
return createNetwork(zoneId, offerings.get(0), caller);
|
||||
}
|
||||
offerings = getApi().listNetworkOfferings("Optional", null, null, null, true, null, null, null, null, null, zoneId);
|
||||
if (offerings != null && !offerings.isEmpty()) {
|
||||
for (CloudStackNetwork network : networks)
|
||||
for (CloudStackNetworkOffering offering : offerings) {
|
||||
logger.debug("[optional] offering: " + offering.getId() + " network " + network.getNetworkOfferingId());
|
||||
if (network.getNetworkOfferingId().equals(offering.getId()))
|
||||
return network;
|
||||
}
|
||||
}
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
// if we get this far and haven't returned already return an error
|
||||
throw new EC2ServiceException(ServerError.InternalError, "Unable to find an appropriate network for account " + caller.getName());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,8 +44,12 @@ public class EC2InstanceFilterSet {
|
|||
filterTypes.put( "instance-state-name", "string" );
|
||||
filterTypes.put( "ip-address", "string" );
|
||||
filterTypes.put( "owner-id", "string" );
|
||||
<<<<<<< HEAD
|
||||
filterTypes.put( "root-device-name", "string" );
|
||||
filterTypes.put( "private-ip-address", "string" );
|
||||
=======
|
||||
filterTypes.put( "root-device-name", "string" );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,10 @@ public class EC2RegisterImage {
|
|||
private String format;
|
||||
private String zoneName;
|
||||
private String osTypeName;
|
||||
<<<<<<< HEAD
|
||||
private String hypervisor;
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
public EC2RegisterImage() {
|
||||
location = null;
|
||||
|
|
@ -60,7 +63,11 @@ public class EC2RegisterImage {
|
|||
|
||||
/**
|
||||
* We redefine the expected format of this field to be:
|
||||
<<<<<<< HEAD
|
||||
* "format:zonename:ostypename:hypervisor"
|
||||
=======
|
||||
* "format:zonename:ostypename"
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
*
|
||||
* @param param
|
||||
*/
|
||||
|
|
@ -71,7 +78,10 @@ public class EC2RegisterImage {
|
|||
format = parts[0];
|
||||
zoneName = parts[1];
|
||||
osTypeName = parts[2];
|
||||
<<<<<<< HEAD
|
||||
hypervisor = parts[3];
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -87,8 +97,11 @@ public class EC2RegisterImage {
|
|||
public String getOsTypeName() {
|
||||
return this.osTypeName;
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
|
||||
public String getHypervisor() {
|
||||
return hypervisor;
|
||||
}
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,11 @@ public class EC2Snapshot {
|
|||
id = null;
|
||||
name = null;
|
||||
volumeId = null;
|
||||
<<<<<<< HEAD
|
||||
volumeSize = new Long(0);
|
||||
=======
|
||||
volumeSize = null;
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
type = null;
|
||||
state = null;
|
||||
created = null;
|
||||
|
|
@ -72,7 +76,11 @@ public class EC2Snapshot {
|
|||
}
|
||||
|
||||
public Long getVolumeSize() {
|
||||
<<<<<<< HEAD
|
||||
return this.volumeSize;
|
||||
=======
|
||||
return this.volumeSize;
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
||||
public void setType( String type ) {
|
||||
|
|
|
|||
|
|
@ -118,7 +118,11 @@ public class EC2VolumeFilterSet {
|
|||
else if (filterName.equalsIgnoreCase( "size" ))
|
||||
return containsLong(vol.getSize(), valueSet );
|
||||
else if (filterName.equalsIgnoreCase( "snapshot-id" ))
|
||||
<<<<<<< HEAD
|
||||
return containsString(String.valueOf(vol.getSnapshotId()), valueSet );
|
||||
=======
|
||||
return containsString(vol.getSnapshotId().toString(), valueSet );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
else if (filterName.equalsIgnoreCase( "status" ))
|
||||
return containsString(vol.getState(), valueSet );
|
||||
else if (filterName.equalsIgnoreCase( "volume-id" ))
|
||||
|
|
@ -128,7 +132,11 @@ public class EC2VolumeFilterSet {
|
|||
else if (filterName.equalsIgnoreCase( "attachment.device" ))
|
||||
return containsDevice(vol.getDeviceId(), valueSet );
|
||||
else if (filterName.equalsIgnoreCase( "attachment.instance-id" ))
|
||||
<<<<<<< HEAD
|
||||
return containsString(String.valueOf(vol.getInstanceId()), valueSet );
|
||||
=======
|
||||
return containsString(vol.getInstanceId().toString(), valueSet );
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
else return false;
|
||||
}
|
||||
|
||||
|
|
@ -167,8 +175,11 @@ public class EC2VolumeFilterSet {
|
|||
|
||||
private boolean containsDevice(String deviceId, String[] set )
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
if (deviceId == null)
|
||||
return false;
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
Integer devId = new Integer(deviceId);
|
||||
for (String s : set) {
|
||||
switch( devId ) {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,12 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
<<<<<<< HEAD
|
||||
* @author Kelven Yang
|
||||
=======
|
||||
* @author Kelven Yang, John Zucker
|
||||
* An S3AccessControlList is simply a holder of grants depicted as instances of S3Grant.
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
*/
|
||||
public class S3AccessControlList {
|
||||
private List<S3Grant> list = new ArrayList<S3Grant>();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.cloud.bridge.service.core.s3;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.activation.DataHandler;
|
||||
|
||||
import com.cloud.bridge.util.OrderedPair;
|
||||
|
||||
/**
|
||||
* @author Kelven Yang
|
||||
*/
|
||||
public interface S3BucketAdapter {
|
||||
void createContainer(String mountedRoot, String bucket);
|
||||
void deleteContainer(String mountedRoot, String bucket);
|
||||
String getBucketFolderDir(String mountedRoot, String bucket);
|
||||
String saveObject(InputStream is, String mountedRoot, String bucket, String fileName);
|
||||
DataHandler loadObject(String mountedRoot, String bucket, String fileName);
|
||||
DataHandler loadObjectRange(String mountedRoot, String bucket, String fileName, long startPos, long endPos);
|
||||
void deleteObject(String mountedRoot, String bucket, String fileName);
|
||||
OrderedPair<String, Long> concatentateObjects(String mountedRoot, String destBucket, String fileName, String sourceBucket, S3MultipartPart[] parts, OutputStream os);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -18,9 +18,22 @@ package com.cloud.bridge.service.core.s3;
|
|||
import java.util.List;
|
||||
|
||||
import com.cloud.bridge.model.SAcl;
|
||||
<<<<<<< HEAD
|
||||
|
||||
/**
|
||||
* @author Kelven Yang
|
||||
=======
|
||||
import com.cloud.bridge.model.SBucket;
|
||||
import com.cloud.bridge.service.exception.UnsupportedException;
|
||||
|
||||
/**
|
||||
* @author Kelven Yang, John Zucker
|
||||
* Each relation holds
|
||||
* a grantee - which is one of SAcl.GRANTEE_USER, SAcl.GRANTEE_ALLUSERS, SAcl.GRANTEE_AUTHENTICATED
|
||||
* a permission - which is one of SAcl.PERMISSION_PASS, SAcl.PERMISSION_NONE, SAcl.PERMISSION_READ,
|
||||
* SAcl.PERMISSION_WRITE, SAcl.PERMISSION_READ_ACL, SAcl.PERMISSION_WRITE_ACL, SAcl.PERMISSION_FULL
|
||||
* canonicalUserID
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
*/
|
||||
public class S3Grant {
|
||||
private int grantee; // SAcl.GRANTEE_USER etc
|
||||
|
|
@ -54,6 +67,12 @@ public class S3Grant {
|
|||
this.canonicalUserID = canonicalUserID;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
/* Return an array of S3Grants holding the permissions of grantees by grantee type and their canonicalUserIds.
|
||||
* Used by S3 engine to get ACL policy requests for buckets and objects.
|
||||
*/
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
public static S3Grant[] toGrants(List<SAcl> grants) {
|
||||
if(grants != null)
|
||||
{
|
||||
|
|
@ -70,4 +89,8 @@ public class S3Grant {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,141 @@
|
|||
package com.cloud.bridge.service.core.s3;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/* @auth John Zucker
|
||||
* Provide a suitable subclass of format class to reflect the choice of bucket referencing format supported by
|
||||
* AWS S3 in constructing the URL for requesting RESTful services. The three possibilities are
|
||||
* (*) hostname followed by bucket as path information (sometimes termed the path style)
|
||||
* (*) bucketname before hostname, so that bucketname appears addressible as a subdomain (termed the subdomain style)
|
||||
* (*) bucketname as a DNS resolvable entry so that path information conveys extra parameters (termed the
|
||||
* virtual hosting style).
|
||||
* The path information is held as a Map of key-value pairs termed pathArgs.
|
||||
* Specification as provided at http://docs.amazonwebservices.com/AmazonS3/latest/dev/VirtualHosting.html.
|
||||
* The class allows for the correct subclass to be selected and the allowable suboptions to be stored.
|
||||
*/
|
||||
|
||||
public abstract class S3HostCallingFormat
|
||||
{
|
||||
protected static S3HostCallingFormat pathStyleHostFormat = new pathStyleHostFormat();
|
||||
protected static S3HostCallingFormat subdomainFormat = new subdomainFormat();
|
||||
protected static S3HostCallingFormat virtualHostingFormat = new virtualHostingFormat();
|
||||
|
||||
// implemented in the returned subclasses
|
||||
public abstract boolean usesLocatedBuckets();
|
||||
// false iff URL is constructed in path style, true otherwise
|
||||
|
||||
public abstract String getEndpoint (String server, int port, String bucket);
|
||||
public abstract String getPathBase (String bucket, String key);
|
||||
|
||||
public abstract URL getURL
|
||||
(boolean isSecure, String server, int port, String bucket, String key, Map<?, ?> pathArgs)
|
||||
throws MalformedURLException;
|
||||
|
||||
public static S3HostCallingFormat getpathStyleHostFormat()
|
||||
{ return pathStyleHostFormat; }
|
||||
|
||||
public static S3HostCallingFormat getsubdomainFormat()
|
||||
{ return subdomainFormat; }
|
||||
|
||||
public static S3HostCallingFormat getvirtualHostingFormat()
|
||||
{
|
||||
return virtualHostingFormat; } // as defined below
|
||||
|
||||
public static String pathArgsMapToString(Map<?, ?> pathArgs)
|
||||
{
|
||||
StringBuffer pathArgsString = new StringBuffer();
|
||||
|
||||
String argument = null;
|
||||
boolean firstArgPosition = true;
|
||||
Iterator<?> argumentIterator;
|
||||
if (pathArgs != null)
|
||||
{
|
||||
for (argumentIterator = pathArgs.keySet().iterator(); argumentIterator.hasNext(); )
|
||||
{
|
||||
argument = (String)argumentIterator.next();
|
||||
pathArgsString.append(firstArgPosition ? "?" : "&");
|
||||
firstArgPosition = false;
|
||||
}
|
||||
}
|
||||
String argumentValue = (String)pathArgs.get(argument);
|
||||
if (argumentValue != null) {
|
||||
pathArgsString.append("=");
|
||||
pathArgsString.append(argumentValue);
|
||||
}
|
||||
return pathArgsString.toString();
|
||||
}
|
||||
|
||||
private static class virtualHostingFormat extends S3HostCallingFormat.subdomainFormat
|
||||
{
|
||||
private virtualHostingFormat()
|
||||
{
|
||||
super();
|
||||
}
|
||||
public String getServer(String server, String bucket)
|
||||
{ return bucket;
|
||||
}
|
||||
}
|
||||
|
||||
private static class subdomainFormat extends S3HostCallingFormat
|
||||
{
|
||||
public boolean usesLocatedBuckets()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getServer(String server, String bucket) {
|
||||
return bucket + "." + server;
|
||||
}
|
||||
public String getEndpoint(String server, int port, String bucket) {
|
||||
return getServer(server, bucket) + ":" + port;
|
||||
}
|
||||
public String getPathBase(String bucket, String key) {
|
||||
return "/" + key;
|
||||
}
|
||||
|
||||
public URL getURL(boolean isSecure, String server, int port, String bucket, String key, Map <?,?> pathArgs) throws MalformedURLException
|
||||
{
|
||||
if ((bucket == null) || (bucket.length() == 0))
|
||||
{
|
||||
String pathArguments = pathArgsMapToString(pathArgs);
|
||||
return new URL(isSecure ? "https" : "http", server, port, "/" + pathArguments);
|
||||
}
|
||||
String serverToUse = getServer(server, bucket);
|
||||
String pathBase = getPathBase(bucket, key);
|
||||
String pathArguments = pathArgsMapToString(pathArgs);
|
||||
return new URL(isSecure ? "https" : "http", serverToUse, port, pathBase + pathArguments);
|
||||
}
|
||||
}
|
||||
|
||||
private static class pathStyleHostFormat extends S3HostCallingFormat
|
||||
{
|
||||
public boolean usesLocatedBuckets()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getPathBase(String bucket, String key) {
|
||||
return isBucketSpecified(bucket) ? "/" + bucket + "/" + key : "/";
|
||||
}
|
||||
|
||||
public String getEndpoint(String server, int port, String bucket) {
|
||||
return server + ":" + port;
|
||||
}
|
||||
|
||||
public URL getURL(boolean isSecure, String server, int port, String bucket, String key, Map<?, ?> pathArgs)
|
||||
throws MalformedURLException
|
||||
{
|
||||
String pathBase = isBucketSpecified(bucket) ? "/" + bucket + "/" + key : "/";
|
||||
String pathArguments = pathArgsMapToString(pathArgs);
|
||||
return new URL(isSecure ? "https" : "http", server, port, pathBase + pathArguments);
|
||||
}
|
||||
|
||||
private boolean isBucketSpecified(String bucket) {
|
||||
if (bucket == null) return false;
|
||||
return bucket.length() != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,10 @@
|
|||
package com.cloud.bridge.service.core.s3;
|
||||
|
||||
import java.util.Calendar;
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
import java.util.TimeZone;
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
/**
|
||||
* @author Kelven Yang
|
||||
|
|
@ -35,8 +39,25 @@ public class S3ListAllMyBucketsEntry {
|
|||
this.name = name;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
public Calendar getCreationDate() {
|
||||
return creationDate;
|
||||
=======
|
||||
public Calendar getCreationDate() {
|
||||
|
||||
// cal.setTimeZone(TimeZone.getTimeZone("Z"));
|
||||
// java.util.Date d = cal.getTime();
|
||||
|
||||
// java.util.Date d = creationDate.getTime();
|
||||
// com.cloud.bridge.util.ISO8601SimpleDateTimeFormat sdf = new com.cloud.bridge.util.ISO8601SimpleDateTimeFormat();
|
||||
// sdf.format(d);
|
||||
// java.lang.StringBuffer b = com.cloud.bridge.util.ISO8601SimpleDateTimeFormat.format(d); return b;
|
||||
|
||||
return creationDate;
|
||||
|
||||
|
||||
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
||||
public void setCreationDate(Calendar creationDate) {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,11 @@ import java.io.InputStream;
|
|||
import javax.activation.DataHandler;
|
||||
|
||||
/**
|
||||
<<<<<<< HEAD
|
||||
* @author Kelven Yang
|
||||
=======
|
||||
* @author Kelven Yang, John Zucker
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
*/
|
||||
public class S3PutObjectInlineRequest extends S3Request {
|
||||
protected String bucketName;
|
||||
|
|
@ -30,7 +34,11 @@ public class S3PutObjectInlineRequest extends S3Request {
|
|||
protected long contentLength;
|
||||
protected S3MetaDataEntry[] metaEntries;
|
||||
protected S3AccessControlList acl;
|
||||
<<<<<<< HEAD
|
||||
protected String cannedAccessPolicy; // -> REST only sets an acl with a simple keyword
|
||||
=======
|
||||
protected String cannedAccessPolicy; // Canned ACLs are public-read, public-read-write, private, authenticated-read or log-delivery-write
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
protected DataHandler data;
|
||||
protected String dataAsString;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,11 @@ package com.cloud.bridge.service.core.s3;
|
|||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
<<<<<<< HEAD
|
||||
* @author Kelven Yang
|
||||
=======
|
||||
* @author Kelven Yang, John Zucker
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
*/
|
||||
public class S3PutObjectInlineResponse extends S3Response {
|
||||
protected String ETag;
|
||||
|
|
@ -31,6 +35,11 @@ public class S3PutObjectInlineResponse extends S3Response {
|
|||
uploadId = -1;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
// add ETag header computed as Base64 MD5 whenever object is uploaded or updated
|
||||
// the Base64 is represented in lowercase
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
public String getETag() {
|
||||
return ETag;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,31 +16,41 @@
|
|||
package com.cloud.bridge.util;
|
||||
|
||||
import java.io.File;
|
||||
<<<<<<< HEAD
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
<<<<<<< HEAD
|
||||
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
|
||||
import org.jasypt.properties.EncryptableProperties;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
/**
|
||||
* @author Kelven Yang
|
||||
*/
|
||||
public class CloudSessionFactory {
|
||||
private static CloudSessionFactory instance;
|
||||
<<<<<<< HEAD
|
||||
public static final Logger logger = Logger.getLogger(CloudSessionFactory.class);
|
||||
=======
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
||||
private SessionFactory factory;
|
||||
|
||||
private CloudSessionFactory() {
|
||||
Configuration cfg = new Configuration();
|
||||
File file = ConfigurationHelper.findConfigurationFile("hibernate.cfg.xml");
|
||||
<<<<<<< HEAD
|
||||
|
||||
File propertiesFile = ConfigurationHelper.findConfigurationFile("db.properties");
|
||||
Properties dbProp = null;
|
||||
|
|
@ -70,10 +80,15 @@ public class CloudSessionFactory {
|
|||
|
||||
|
||||
//
|
||||
=======
|
||||
|
||||
//
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
// we are packaging hibernate mapping files along with the class files,
|
||||
// make sure class loader use the same class path when initializing hibernate mapping.
|
||||
// This is important when we are deploying and testing at different environment (Tomcat/JUnit test runner)
|
||||
//
|
||||
<<<<<<< HEAD
|
||||
if(file != null && dbProp != null){
|
||||
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
|
||||
cfg.configure(file);
|
||||
|
|
@ -94,6 +109,10 @@ public class CloudSessionFactory {
|
|||
logger.warn("Unable to open load db configuration");
|
||||
throw new RuntimeException("nable to open load db configuration");
|
||||
}
|
||||
=======
|
||||
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
|
||||
factory = cfg.configure(file).buildSessionFactory();
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
}
|
||||
|
||||
public synchronized static CloudSessionFactory getInstance() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.cloud.bridge.util;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.axis2.databinding.utils.ConverterUtil;
|
||||
|
||||
/**
|
||||
* @author John Zucker
|
||||
* Custom subclass of org.apache.axis2.databinding.utils.ConverterUtil, i.e. the data conversion utility for
|
||||
* databindings in the ADB framework of Axis2. The purpose of a custom class is to provide specific value
|
||||
* format conversions for certain datatypes, especially dates, timestamps and calendars for which the default
|
||||
* is inappropriate. For these simple cases, the return value is of type String.
|
||||
* Converter methods to go from 1. simple type -> String 2. simple type -> Object 3. String ->
|
||||
* simpletype 4. Object list -> array
|
||||
*/
|
||||
|
||||
|
||||
public class DatabindingConverterUtil extends ConverterUtil {
|
||||
|
||||
// Custom behaviour for java.util.Date
|
||||
public static String convertToString(Date dateValue)
|
||||
{
|
||||
|
||||
return (new ISO8601SimpleDateTimeFormat()).format(dateValue);
|
||||
}
|
||||
|
||||
// Custom behaviour for java.util.Calendar
|
||||
public static String convertToString(Calendar calendarValue)
|
||||
{
|
||||
|
||||
return (new ISO8601SimpleDateTimeFormat()).format(calendarValue.getTime());
|
||||
}
|
||||
|
||||
// Custom behaviour for java.sql.Timestamp
|
||||
public static String convertToString(Timestamp timestampValue)
|
||||
{
|
||||
|
||||
return timestampValue.toString();
|
||||
}
|
||||
|
||||
// Otherwise String convertToString(Object any) is handled by invoker (which happens to be superclass).
|
||||
// No need to reference super explicitly because it is the invoker of static methods
|
||||
// @see org.apache.axis2.databinding.utils.ConverterUtil
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -5,11 +5,23 @@ public class HeaderParam {
|
|||
protected String name;
|
||||
protected String value;
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
public HeaderParam() {
|
||||
name = null;
|
||||
value = null;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
public HeaderParam (String name, String value) {
|
||||
this.name = name;
|
||||
this.name = value;
|
||||
}
|
||||
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
public void setName( String name ) {
|
||||
this.name = name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,353 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.cloud.bridge.util;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.FieldPosition;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParsePosition;
|
||||
import java.util.Date;
|
||||
import java.util.Calendar;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* @author John Zucker
|
||||
* Format and parse a date string which is expected to be in ISO 8601 DateTimeFormat especially for
|
||||
* use in XML documents.
|
||||
* An example is for use with GMTDateTimeUserType to provide parsing of DateTime format strings into
|
||||
* accurate Java Date representations based on UTC.
|
||||
* The purpose of this class is to allow the creation of accurate date time representations following
|
||||
* the ISO 8601 format YYYY-MM-DDThh:MM:ss
|
||||
* using the letter "T" as the date/time separator
|
||||
* This representation may be immediately followed by a "Z" (Zulu i.e. at zero offset from GMT) to indicate UTC
|
||||
* or, otherwise, to a specific time zone. If a time zone (tz) is encoded then this is held as the difference
|
||||
* between the local time in the tz and UCT, expressed as a positive(+) or negative(-) offset (hhMM) appended
|
||||
* to the format.
|
||||
* The default case holds no tz information and assumes that a date time representation referenced to Zulu
|
||||
* (i.e. zero offset from GMT) is required. When formatting an existing Date transform it into the Zulu timezone
|
||||
* so that it is explicitly at GMT with zero offset. This provides the default representation for the encoding
|
||||
* of AWS datetime values.
|
||||
* For testing, it may be useful to note that, as at 2012, a city whose time is always in the Zulu timezone is
|
||||
* Reykjavik, Iceland.
|
||||
* The parsing and formatting methods provided by this class are GMT-referenced and locale insensitive.
|
||||
*/
|
||||
|
||||
public class ISO8601SimpleDateTimeFormat extends SimpleDateFormat {
|
||||
|
||||
private static final long serialVersionUID = 7388260211953189670L;
|
||||
|
||||
protected static TimeZone defaultTimeZone = TimeZone.getTimeZone("Z");
|
||||
|
||||
/**
|
||||
* Construct a new ISO8601DateTimeFormat using the default time zone.
|
||||
* Initializes calendar inherited from java.text.DateFormat.calendar
|
||||
*
|
||||
*/
|
||||
public ISO8601SimpleDateTimeFormat() {
|
||||
setCalendar(Calendar.getInstance(defaultTimeZone));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new ISO8601DateTimeFormat using a specific time zone.
|
||||
* Initializes calendar inherited from java.text.DateFormat.calendar
|
||||
* @param tz The time zone used to format and parse the date.
|
||||
*/
|
||||
public ISO8601SimpleDateTimeFormat(TimeZone tz) {
|
||||
setCalendar(Calendar.getInstance(tz));
|
||||
}
|
||||
|
||||
/**
|
||||
* The abstract superclass DateFormat has two business methods to override. These are
|
||||
* public StringBuffer format(Date arg0, StringBuffer arg1, FieldPosition arg2)
|
||||
* public Date parse(String arg0, ParsePosition arg1)
|
||||
*/
|
||||
|
||||
/**
|
||||
* @see DateFormat#format(Date, StringBuffer, FieldPosition)
|
||||
*/
|
||||
@Override
|
||||
public StringBuffer format(Date date, StringBuffer stringBuffer, FieldPosition fieldPosition) {
|
||||
calendar.setTime(date);
|
||||
calendar.setTimeZone(defaultTimeZone);
|
||||
writeYYYYMM(stringBuffer);
|
||||
stringBuffer.append('T');
|
||||
writehhMMss(stringBuffer);
|
||||
stringBuffer.append(".000Z");
|
||||
return stringBuffer;
|
||||
}
|
||||
|
||||
/* @see DateFormat#parse(String, ParsePosition)
|
||||
* Assigns the values of YYYY-MM-DDThh:MM:ss fields between the delimiters of dateString
|
||||
* or a near approximation using the superclass SimpleDateFormat if not formatted exactly as ISO8601
|
||||
*/
|
||||
@Override
|
||||
public Date parse(String dateString, ParsePosition pos) {
|
||||
ParsePosition startpos = pos;
|
||||
int p = pos.getIndex();
|
||||
// Assign value of YYYY
|
||||
try {
|
||||
int YYYY = Integer.valueOf(dateString.substring(p, p + 4)).intValue();
|
||||
p += 4;
|
||||
if (dateString.charAt(p) != '-') {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
p++;
|
||||
// Assign value of MM
|
||||
int MM = Integer.valueOf(dateString.substring(p, p + 2)).intValue() - 1;
|
||||
p += 2;
|
||||
if (dateString.charAt(p) != '-') {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
p++;
|
||||
// Asign value of dd
|
||||
int DD = Integer.valueOf(dateString.substring(p, p + 2)).intValue();
|
||||
p += 2;
|
||||
if (dateString.charAt(p) != 'T') {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
p++;
|
||||
// Assign value of hh
|
||||
int hh = Integer.valueOf(dateString.substring(p, p + 2)).intValue();
|
||||
p += 2;
|
||||
if (dateString.charAt(p) != ':') {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
p++;
|
||||
// Assign value of mm
|
||||
int mm = Integer.valueOf(dateString.substring(p, p + 2)).intValue();
|
||||
p += 2;
|
||||
if (dateString.charAt(p) != ':') {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
p++;
|
||||
// Assign value of ss
|
||||
int ss = 0;
|
||||
// if (p < dateString.length() && dateString.charAt(p) == ':') {
|
||||
// Allow exactly two ss digits after final : delimiter
|
||||
ss = Integer.valueOf(dateString.substring(p, p + 2)).intValue();
|
||||
p += 2;
|
||||
// Set calendar inherited from java.text.DateFormat.calendar
|
||||
calendar.set(YYYY, MM, DD, hh, mm, ss);
|
||||
calendar.set(Calendar.MILLISECOND, 0); // Since java.util.Date holds none, zeroize milliseconds
|
||||
// process appended timezone if any or Z otherwise
|
||||
p = parseTZ(p, dateString);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
super.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
super.applyPattern("yyyy-MM-dd HH:mm:ss");
|
||||
return super.parse(dateString, startpos);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
super.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
return super.parse(dateString, startpos); // default pattern
|
||||
}
|
||||
finally
|
||||
{
|
||||
pos.setIndex(p);
|
||||
}
|
||||
// Return the Calendar instance's Date representation of its value
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the time zone string. Remember that in the default TimeZone there is no offset and the
|
||||
* convention to supply the TimeZone string constant "Z" is applicable. As an optimization there
|
||||
* is no need to call this method where the default TimeZone has been set.
|
||||
* @param stringBuffer The buffer to append the time zone.
|
||||
*/
|
||||
protected final void writeTZ(StringBuffer stringBuffer) {
|
||||
int offset =
|
||||
calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
|
||||
if (offset == 0) {
|
||||
stringBuffer.append('Z');
|
||||
}
|
||||
else {
|
||||
int offsetHour = offset / 3600000;
|
||||
int offsetMin = (offset % 3600000) / 60000;
|
||||
if (offset >= 0) {
|
||||
stringBuffer.append('+');
|
||||
}
|
||||
else {
|
||||
stringBuffer.append('-');
|
||||
offsetHour = 0 - offsetHour;
|
||||
offsetMin = 0 - offsetMin;
|
||||
}
|
||||
appendInt(stringBuffer, offsetHour, 2);
|
||||
stringBuffer.append(':');
|
||||
appendInt(stringBuffer, offsetMin, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write hour, minutes, and seconds.
|
||||
* @param stringBuffer The buffer to append the string.
|
||||
*/
|
||||
protected final void writehhMMss(StringBuffer stringBuffer) {
|
||||
int hh = calendar.get(Calendar.HOUR_OF_DAY);
|
||||
appendInt(stringBuffer, hh, 2);
|
||||
stringBuffer.append(':');
|
||||
|
||||
int mm = calendar.get(Calendar.MINUTE);
|
||||
appendInt(stringBuffer, mm, 2);
|
||||
stringBuffer.append(':');
|
||||
|
||||
int ss = calendar.get(Calendar.SECOND);
|
||||
appendInt(stringBuffer, ss, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write YYYY, and MMs.
|
||||
* @param stringBuffer The buffer to append the string.
|
||||
*/
|
||||
protected final void writeYYYYMM(StringBuffer stringBuffer) {
|
||||
int YYYY = calendar.get(Calendar.YEAR);
|
||||
appendInt(stringBuffer, YYYY, 4);
|
||||
|
||||
String MM;
|
||||
switch (calendar.get(Calendar.MONTH)) {
|
||||
case Calendar.JANUARY :
|
||||
MM = "-01-";
|
||||
break;
|
||||
case Calendar.FEBRUARY :
|
||||
MM = "-02-";
|
||||
break;
|
||||
case Calendar.MARCH :
|
||||
MM = "-03-";
|
||||
break;
|
||||
case Calendar.APRIL :
|
||||
MM = "-04-";
|
||||
break;
|
||||
case Calendar.MAY :
|
||||
MM = "-05-";
|
||||
break;
|
||||
case Calendar.JUNE :
|
||||
MM = "-06-";
|
||||
break;
|
||||
case Calendar.JULY :
|
||||
MM = "-07-";
|
||||
break;
|
||||
case Calendar.AUGUST :
|
||||
MM = "-08-";
|
||||
break;
|
||||
case Calendar.SEPTEMBER :
|
||||
MM = "-09-";
|
||||
break;
|
||||
case Calendar.OCTOBER :
|
||||
MM = "-10-";
|
||||
break;
|
||||
case Calendar.NOVEMBER :
|
||||
MM = "-11-";
|
||||
break;
|
||||
case Calendar.DECEMBER :
|
||||
MM = "-12-";
|
||||
break;
|
||||
default :
|
||||
MM = "-NA-";
|
||||
break;
|
||||
}
|
||||
stringBuffer.append(MM);
|
||||
|
||||
int DD = calendar.get(Calendar.DAY_OF_MONTH);
|
||||
appendInt(stringBuffer, DD, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an integer value with leading zeros.
|
||||
* @param stringBuffer The buffer to append the string.
|
||||
* @param value The value to write.
|
||||
* @param length The length of the string to write.
|
||||
*/
|
||||
protected final void appendInt(StringBuffer stringBuffer, int value, int length) {
|
||||
int len1 = stringBuffer.length();
|
||||
stringBuffer.append(value);
|
||||
int len2 = stringBuffer.length();
|
||||
for (int i = len2; i < len1 + length; ++i) {
|
||||
stringBuffer.insert(len1, '0');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the time zone.
|
||||
* @param i The position to start parsing.
|
||||
* @param dateString The dateString to parse.
|
||||
* @return The position after parsing has finished.
|
||||
*/
|
||||
|
||||
protected final int parseTZ(int i, String dateString) {
|
||||
if (i < dateString.length()) {
|
||||
// check and handle the zone/dst offset
|
||||
int offset = 0;
|
||||
if (dateString.charAt(i) == 'Z') {
|
||||
offset = 0;
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
int sign = 1;
|
||||
if (dateString.charAt(i) == '-') {
|
||||
sign = -1;
|
||||
}
|
||||
else if (dateString.charAt(i) != '+') {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
i++;
|
||||
|
||||
int offsetHour = Integer.valueOf(dateString.substring(i, i + 2)).intValue();
|
||||
i += 2;
|
||||
|
||||
if (dateString.charAt(i) != ':') {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
i++;
|
||||
|
||||
int offsetMin = Integer.valueOf(dateString.substring(i, i + 2)).intValue();
|
||||
i += 2;
|
||||
offset = ((offsetHour * 60) + offsetMin) * 60000 * sign;
|
||||
}
|
||||
int offsetCal =
|
||||
calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
|
||||
|
||||
calendar.add(Calendar.MILLISECOND, offsetCal - offset);
|
||||
}
|
||||
return i;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (calendar.get(2)+calendar.get(16));
|
||||
// numberFormat (used by superclass) will not distribute, so use calendar third and penultimate fields
|
||||
// (i.e. dd and ss) instead
|
||||
// in Java 6 (Calendar.FIELD_COUNT-1) returns 16
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null || getClass() != obj.getClass()) return false;
|
||||
DateFormat other = (DateFormat) obj;
|
||||
Calendar otherCalendar = other.getCalendar();
|
||||
for (int i = 0; i < Calendar.FIELD_COUNT; i++)
|
||||
if ( calendar.get(i) != (otherCalendar.get(i)) ) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.cloud.bridge.util;
|
||||
|
||||
/**
|
||||
* @author Kelven Yang, John Zucker
|
||||
* Reusable class whose instances encode any ordered pair (or 2-tuple) of values of types T1 and T2
|
||||
* Provide getters: getFirst(), getSecond()
|
||||
* Provide setters: setFirst(val), setSecond(val)
|
||||
* @param <T1>
|
||||
* @param <T2>
|
||||
*/
|
||||
public class OrderedPair <T1, T2> {
|
||||
T1 first;
|
||||
T2 second;
|
||||
|
||||
public OrderedPair(T1 t1, T2 t2) {
|
||||
first = t1;
|
||||
second = t2;
|
||||
}
|
||||
|
||||
public T1 getFirst() {
|
||||
return first;
|
||||
}
|
||||
|
||||
public OrderedPair<T1, T2> setFirst(T1 t1) {
|
||||
first = t1;
|
||||
return this;
|
||||
}
|
||||
|
||||
public T2 getSecond() {
|
||||
return second;
|
||||
}
|
||||
|
||||
public OrderedPair<T1, T2> setSecond(T2 t2) {
|
||||
second = t2;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
/*
|
||||
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved.
|
||||
*
|
||||
|
|
@ -357,3 +358,407 @@ public class RestAuth {
|
|||
return result.trim();
|
||||
}
|
||||
}
|
||||
=======
|
||||
/*
|
||||
* Copyright (C) 2011 Citrix Systems, Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.cloud.bridge.util;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.SignatureException;
|
||||
import java.util.*;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* This class expects that the caller pulls the required headers from the standard
|
||||
* HTTPServeletRequest structure. This class is responsible for providing the
|
||||
* RFC2104 calculation to ensure that the signature is valid for the signing string.
|
||||
* The signing string is a representation of the request.
|
||||
* Notes are given below on what values are expected.
|
||||
* This class is used for the Authentication check for REST requests and Query String
|
||||
* Authentication requests.
|
||||
*
|
||||
* @author Kelven Yang, John Zucker, Salvatore Orlando
|
||||
*/
|
||||
|
||||
public class RestAuth {
|
||||
protected final static Logger logger = Logger.getLogger(RestAuth.class);
|
||||
|
||||
// TreeMap: used when constructing the CanonicalizedAmzHeaders Element of the StringToSign
|
||||
protected TreeMap<String, String> AmazonHeaders = null; // not always present
|
||||
protected String bucketName = null; // not always present
|
||||
protected String queryString = null; // for CanonicalizedResource - only interested in a string starting with particular values
|
||||
protected String uriPath = null; // only interested in the resource path
|
||||
protected String date = null; // only if x-amz-date is not set
|
||||
protected String contentType = null; // not always present
|
||||
protected String contentMD5 = null; // not always present
|
||||
protected boolean amzDateSet = false;
|
||||
protected boolean useSubDomain = false;
|
||||
|
||||
protected Set<String> allowedQueryParams;
|
||||
|
||||
public RestAuth() {
|
||||
// these must be lexicographically sorted
|
||||
AmazonHeaders = new TreeMap<String, String>();
|
||||
allowedQueryParams = new HashSet<String>() {{
|
||||
add("acl");
|
||||
add("lifecycle");
|
||||
add("location");
|
||||
add("logging");
|
||||
add("notification");
|
||||
add("partNumber");
|
||||
add("policy");
|
||||
add("requestPayment");
|
||||
add("torrent");
|
||||
add("uploadId");
|
||||
add("uploads");
|
||||
add("versionId");
|
||||
add("versioning");
|
||||
add("versions");
|
||||
add("website");
|
||||
}};
|
||||
}
|
||||
|
||||
public RestAuth(boolean useSubDomain) {
|
||||
//invoke the other constructor
|
||||
this();
|
||||
this.useSubDomain = useSubDomain;
|
||||
}
|
||||
|
||||
public void setUseSubDomain(boolean value) {
|
||||
useSubDomain = value;
|
||||
}
|
||||
|
||||
public boolean getUseSubDomain() {
|
||||
return useSubDomain;
|
||||
}
|
||||
|
||||
/**
|
||||
* This header is used iff the "x-amz-date:" header is not defined.
|
||||
* Value is used in constructing the StringToSign for signature verification.
|
||||
*
|
||||
* @param date - the contents of the "Date:" header, skipping the 'Date:' preamble.
|
||||
* OR pass in the value of the "Expires=" query string parameter passed in
|
||||
* for "Query String Authentication".
|
||||
*/
|
||||
public void setDateHeader( String date ) {
|
||||
if (this.amzDateSet) return;
|
||||
if (null != date) date = date.trim();
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Value is used in constructing the StringToSign for signature verification.
|
||||
*
|
||||
* @param type - the contents of the "Content-Type:" header, skipping the 'Content-Type:' preamble.
|
||||
*/
|
||||
public void setContentTypeHeader( String type ) {
|
||||
if (null != type) type = type.trim();
|
||||
this.contentType = type;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Value is used in constructing the StringToSign for signature verification.
|
||||
* @param type - the contents of the "Content-MD5:" header, skipping the 'Content-MD5:' preamble.
|
||||
*/
|
||||
public void setContentMD5Header( String md5 ) {
|
||||
if (null != md5) md5 = md5.trim();
|
||||
this.contentMD5 = md5;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The bucket name can be in the "Host:" header but it does not have to be. It can
|
||||
* instead be in the uriPath as the first step in the path.
|
||||
*
|
||||
* Used as part of the CanonalizedResource element of the StringToSign.
|
||||
* If we get "Host: static.johnsmith.net:8080", then the bucket name is "static.johnsmith.net"
|
||||
*
|
||||
* @param header - contents of the "Host:" header, skipping the 'Host:' preamble.
|
||||
*/
|
||||
public void setHostHeader( String header ) {
|
||||
if (null == header) {
|
||||
this.bucketName = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// -> is there a port on the name?
|
||||
header = header.trim();
|
||||
int offset = header.indexOf( ":" );
|
||||
if (-1 != offset) header = header.substring( 0, offset );
|
||||
this.bucketName = header;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used as part of the CanonalizedResource element of the StringToSign.
|
||||
* CanonicalizedResource = [ "/" + Bucket ] +
|
||||
* <HTTP-Request-URI, from the protocol name up to the query string> + [sub-resource]
|
||||
* The list of sub-resources that must be included when constructing the CanonicalizedResource Element are: acl, lifecycle, location,
|
||||
* logging, notification, partNumber, policy, requestPayment, torrent, uploadId, uploads, versionId, versioning, versions and website.
|
||||
* (http://docs.amazonwebservices.com/AmazonS3/latest/dev/RESTAuthentication.html)
|
||||
* @param query - results from calling "HttpServletRequest req.getQueryString()"
|
||||
*/
|
||||
public void setQueryString( String query ) {
|
||||
if (null == query) {
|
||||
this.queryString = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// Sub-resources (i.e.: query params) must be lex sorted
|
||||
Set<String> subResources = new TreeSet<String>();
|
||||
|
||||
String [] queryParams = query.split("&");
|
||||
StringBuffer builtQuery= new StringBuffer();
|
||||
for (String queryParam:queryParams) {
|
||||
// lookup parameter name
|
||||
String paramName = queryParam.split("=")[0];
|
||||
if (allowedQueryParams.contains(paramName)) {
|
||||
subResources.add(queryParam);
|
||||
}
|
||||
}
|
||||
for (String subResource:subResources) {
|
||||
builtQuery.append(subResource + "&");
|
||||
}
|
||||
// If anything inside the string buffer, add a "?" at the beginning,
|
||||
// and then remove the last '&'
|
||||
if (builtQuery.length() > 0) {
|
||||
builtQuery.insert(0, "?");
|
||||
builtQuery.deleteCharAt(builtQuery.length()-1);
|
||||
}
|
||||
this.queryString = builtQuery.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used as part of the CanonalizedResource element of the StringToSign.
|
||||
* Append the path part of the un-decoded HTTP Request-URI, up-to but not including the query string.
|
||||
*
|
||||
* @param path - - results from calling "HttpServletRequest req.getPathInfo()"
|
||||
*/
|
||||
public void addUriPath( String path ) {
|
||||
if (null != path) path = path.trim();
|
||||
this.uriPath = path;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pass in each complete Amazon header found in the HTTP request one at a time.
|
||||
* Each Amazon header added will become part of the signature calculation.
|
||||
* We are using a TreeMap here because of the S3 definition:
|
||||
* "Sort the collection of headers lexicographically by header name."
|
||||
*
|
||||
* @param headerAndValue - needs to be the complete amazon header (i.e., starts with "x-amz").
|
||||
*/
|
||||
public void addAmazonHeader( String headerAndValue ) {
|
||||
if (null == headerAndValue) return;
|
||||
|
||||
String canonicalized = null;
|
||||
|
||||
// [A] First Canonicalize the header and its value
|
||||
// -> we use the header 'name' as the key since we have to sort on that
|
||||
int offset = headerAndValue.indexOf( ":" );
|
||||
String header = headerAndValue.substring( 0, offset+1 ).toLowerCase();
|
||||
String value = headerAndValue.substring( offset+1 ).trim();
|
||||
|
||||
// -> RFC 2616, Section 4.2: unfold the header's value by replacing linear white space with a single space character
|
||||
// -> does the HTTPServeletReq already do this for us?
|
||||
value = value.replaceAll( " ", " " ); // -> multiple spaces to one space
|
||||
value = value.replaceAll( "(\r\n|\t|\n)", " " ); // -> CRLF, tab, and LF to one space
|
||||
|
||||
|
||||
// [B] Does this header already exist?
|
||||
if ( AmazonHeaders.containsKey( header )) {
|
||||
// -> combine header fields with the same name into one "header-name:comma-separated-value-list" pair as prescribed by RFC 2616, section 4.2, without any white-space between values.
|
||||
canonicalized = AmazonHeaders.get( header );
|
||||
canonicalized = new String( canonicalized + "," + value + "\n" );
|
||||
canonicalized = canonicalized.replaceAll( "\n,", "," ); // remove the '\n' from the first stored value
|
||||
}
|
||||
else canonicalized = new String( header + value + "\n" ); // -> as per spec, no space between header and its value
|
||||
|
||||
AmazonHeaders.put( header, canonicalized );
|
||||
|
||||
// [C] "x-amz-date:" takes precedence over the "Date:" header
|
||||
if (header.equals( "x-amz-date:" )) {
|
||||
this.amzDateSet = true;
|
||||
if (null != this.date) this.date = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The request is authenticated if we can regenerate the same signature given
|
||||
* on the request. Before calling this function make sure to set the header values
|
||||
* defined by the public values above.
|
||||
*
|
||||
* @param httpVerb - the type of HTTP request (e.g., GET, PUT)
|
||||
* @param secretKey - value obtained from the AWSAccessKeyId
|
||||
* @param signature - the signature we are trying to recreate, note can be URL-encoded
|
||||
*
|
||||
* @throws SignatureException
|
||||
*
|
||||
* @return true if request has been authenticated, false otherwise
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
|
||||
public boolean verifySignature( String httpVerb, String secretKey, String signature )
|
||||
throws SignatureException, UnsupportedEncodingException {
|
||||
|
||||
if (null == httpVerb || null == secretKey || null == signature) return false;
|
||||
|
||||
httpVerb = httpVerb.trim();
|
||||
secretKey = secretKey.trim();
|
||||
signature = signature.trim();
|
||||
|
||||
// First calculate the StringToSign after the caller has initialized all the header values
|
||||
String StringToSign = genStringToSign( httpVerb );
|
||||
String calSig = calculateRFC2104HMAC( StringToSign, secretKey );
|
||||
// Was the passed in signature URL encoded? (it must be base64 encoded)
|
||||
int offset = signature.indexOf( "%" );
|
||||
if (-1 != offset) signature = URLDecoder.decode( signature, "UTF-8" );
|
||||
|
||||
boolean match = signature.equals( calSig );
|
||||
if (!match)
|
||||
logger.error( "Signature mismatch, [" + signature + "] [" + calSig + "] over [" + StringToSign + "]" );
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function generates the single string that will be used to sign with a users
|
||||
* secret key.
|
||||
*
|
||||
* StringToSign = HTTP-Verb + "\n" +
|
||||
* Content-MD5 + "\n" +
|
||||
* Content-Type + "\n" +
|
||||
* Date + "\n" +
|
||||
* CanonicalizedAmzHeaders +
|
||||
* CanonicalizedResource;
|
||||
*
|
||||
* @return The single StringToSign or null.
|
||||
*/
|
||||
private String genStringToSign( String httpVerb ) {
|
||||
StringBuffer canonicalized = new StringBuffer();
|
||||
String temp = null;
|
||||
String canonicalizedResourceElement = genCanonicalizedResourceElement();
|
||||
canonicalized.append( httpVerb ).append( "\n" );
|
||||
if ( (null != this.contentMD5) )
|
||||
canonicalized.append( this.contentMD5 );
|
||||
canonicalized.append( "\n" );
|
||||
|
||||
if ( (null != this.contentType) )
|
||||
canonicalized.append( this.contentType );
|
||||
canonicalized.append( "\n" );
|
||||
|
||||
if (null != this.date)
|
||||
canonicalized.append( this.date );
|
||||
|
||||
canonicalized.append( "\n" );
|
||||
|
||||
if (null != (temp = genCanonicalizedAmzHeadersElement())) canonicalized.append( temp );
|
||||
if (null != canonicalizedResourceElement) canonicalized.append( canonicalizedResourceElement );
|
||||
|
||||
if ( 0 == canonicalized.length())
|
||||
return null;
|
||||
|
||||
return canonicalized.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CanonicalizedResource represents the Amazon S3 resource targeted by the request.
|
||||
* CanonicalizedResource = [ "/" + Bucket ] +
|
||||
* <HTTP-Request-URI, from the protocol name up to the query string> +
|
||||
* [ sub-resource, if present. For example "?acl", "?location", "?logging", or "?torrent"];
|
||||
*
|
||||
* @return A single string representing CanonicalizedResource or null.
|
||||
*/
|
||||
private String genCanonicalizedResourceElement() {
|
||||
StringBuffer canonicalized = new StringBuffer();
|
||||
|
||||
if(this.useSubDomain && this.bucketName != null)
|
||||
canonicalized.append( "/" ).append( this.bucketName );
|
||||
|
||||
if (null != this.uriPath ) canonicalized.append( this.uriPath );
|
||||
if (null != this.queryString) canonicalized.append( this.queryString );
|
||||
|
||||
if ( 0 == canonicalized.length())
|
||||
return null;
|
||||
|
||||
return canonicalized.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct the Canonicalized Amazon headers element of the StringToSign by
|
||||
* concatenating all headers in the TreeMap into a single string.
|
||||
*
|
||||
* @return A single string with all the Amazon headers glued together, or null
|
||||
* if no Amazon headers appeared in the request.
|
||||
*/
|
||||
private String genCanonicalizedAmzHeadersElement() {
|
||||
Collection<String> headers = AmazonHeaders.values();
|
||||
Iterator<String> itr = headers.iterator();
|
||||
StringBuffer canonicalized = new StringBuffer();
|
||||
|
||||
while( itr.hasNext())
|
||||
canonicalized.append( itr.next());
|
||||
|
||||
if ( 0 == canonicalized.length())
|
||||
return null;
|
||||
|
||||
return canonicalized.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a signature by the following method:
|
||||
* new String( Base64( SHA1( key, byte array )))
|
||||
*
|
||||
* @param signIt - the data to generate a keyed HMAC over
|
||||
* @param secretKey - the user's unique key for the HMAC operation
|
||||
* @return String - the recalculated string
|
||||
* @throws SignatureException
|
||||
*/
|
||||
private String calculateRFC2104HMAC( String signIt, String secretKey )
|
||||
throws SignatureException {
|
||||
String result = null;
|
||||
try {
|
||||
SecretKeySpec key = new SecretKeySpec( secretKey.getBytes(), "HmacSHA1" );
|
||||
Mac hmacSha1 = Mac.getInstance( "HmacSHA1" );
|
||||
hmacSha1.init( key );
|
||||
byte [] rawHmac = hmacSha1.doFinal( signIt.getBytes());
|
||||
result = new String( Base64.encodeBase64( rawHmac ));
|
||||
}
|
||||
catch( InvalidKeyException e ) {
|
||||
throw new SignatureException( "Failed to generate keyed HMAC on REST request because key " + secretKey + " is invalid" + e.getMessage());
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new SignatureException( "Failed to generate keyed HMAC on REST request: " + e.getMessage());
|
||||
}
|
||||
return result.trim();
|
||||
}
|
||||
}
|
||||
>>>>>>> 6472e7b... Now really adding the renamed files!
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue