diff --git a/awsapi-setup/db/mysql/cloudbridge_db.sql b/awsapi-setup/db/mysql/cloudbridge_db.sql index 6a4a6894056..c30e4b51199 100644 --- a/awsapi-setup/db/mysql/cloudbridge_db.sql +++ b/awsapi-setup/db/mysql/cloudbridge_db.sql @@ -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! diff --git a/awsapi-setup/setup/cloud-bridge-register b/awsapi-setup/setup/cloud-bridge-register index e199feefec5..6f9690cc237 100644 --- a/awsapi-setup/setup/cloud-bridge-register +++ b/awsapi-setup/setup/cloud-bridge-register @@ -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) diff --git a/awsapi-setup/setup/cloud-setup-bridge-db b/awsapi-setup/setup/cloud-setup-bridge-db new file mode 100755 index 00000000000..435ba5c5a1e --- /dev/null +++ b/awsapi-setup/setup/cloud-setup-bridge-db @@ -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) diff --git a/awsapi-setup/tomcat/catalina.policy b/awsapi-setup/tomcat/catalina.policy new file mode 100644 index 00000000000..4bbfbf29058 --- /dev/null +++ b/awsapi-setup/tomcat/catalina.policy @@ -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"; +// }; + diff --git a/awsapi-setup/tomcat/catalina.properties b/awsapi-setup/tomcat/catalina.properties new file mode 100644 index 00000000000..dc2db354920 --- /dev/null +++ b/awsapi-setup/tomcat/catalina.properties @@ -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 diff --git a/awsapi-setup/tomcat/classpath.conf b/awsapi-setup/tomcat/classpath.conf new file mode 100644 index 00000000000..b00e8f5e6f1 --- /dev/null +++ b/awsapi-setup/tomcat/classpath.conf @@ -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 diff --git a/awsapi-setup/tomcat/components.xml b/awsapi-setup/tomcat/components.xml new file mode 100644 index 00000000000..5f1d7fd299e --- /dev/null +++ b/awsapi-setup/tomcat/components.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + diff --git a/awsapi-setup/tomcat/context.xml b/awsapi-setup/tomcat/context.xml new file mode 100644 index 00000000000..9913dd149a4 --- /dev/null +++ b/awsapi-setup/tomcat/context.xml @@ -0,0 +1,35 @@ + + + + + + + WEB-INF/web.xml + + + + + + + + diff --git a/awsapi-setup/tomcat/ehcache.xml b/awsapi-setup/tomcat/ehcache.xml new file mode 100644 index 00000000000..c65deeacdb9 --- /dev/null +++ b/awsapi-setup/tomcat/ehcache.xml @@ -0,0 +1,527 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/awsapi-setup/tomcat/logging.properties b/awsapi-setup/tomcat/logging.properties new file mode 100644 index 00000000000..68be2d7f457 --- /dev/null +++ b/awsapi-setup/tomcat/logging.properties @@ -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 diff --git a/awsapi-setup/tomcat/server.xml b/awsapi-setup/tomcat/server.xml new file mode 100644 index 00000000000..4eb16e3485c --- /dev/null +++ b/awsapi-setup/tomcat/server.xml @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/awsapi-setup/tomcat/tomcat-users.xml b/awsapi-setup/tomcat/tomcat-users.xml new file mode 100644 index 00000000000..81422a02892 --- /dev/null +++ b/awsapi-setup/tomcat/tomcat-users.xml @@ -0,0 +1,31 @@ + + + + + + + + + + diff --git a/awsapi-setup/tomcat/tomcat6.conf b/awsapi-setup/tomcat/tomcat6.conf new file mode 100644 index 00000000000..75b9a988b2a --- /dev/null +++ b/awsapi-setup/tomcat/tomcat6.conf @@ -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 diff --git a/awsapi-setup/tomcat/web.xml b/awsapi-setup/tomcat/web.xml new file mode 100644 index 00000000000..44b6eab07fe --- /dev/null +++ b/awsapi-setup/tomcat/web.xml @@ -0,0 +1,1188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default + org.apache.catalina.servlets.DefaultServlet + + debug + 0 + + + listings + false + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + jsp + org.apache.jasper.servlet.JspServlet + + fork + false + + + xpoweredBy + false + + 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default + / + + + + + + + + jsp + *.jsp + + + + jsp + *.jspx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30 + + + + + + + + + + + + abs + audio/x-mpeg + + + ai + application/postscript + + + aif + audio/x-aiff + + + aifc + audio/x-aiff + + + aiff + audio/x-aiff + + + aim + application/x-aim + + + art + image/x-jg + + + asf + video/x-ms-asf + + + asx + video/x-ms-asf + + + au + audio/basic + + + avi + video/x-msvideo + + + avx + video/x-rad-screenplay + + + bcpio + application/x-bcpio + + + bin + application/octet-stream + + + bmp + image/bmp + + + body + text/html + + + cdf + application/x-cdf + + + cer + application/x-x509-ca-cert + + + class + application/java + + + cpio + application/x-cpio + + + csh + application/x-csh + + + css + text/css + + + dib + image/bmp + + + doc + application/msword + + + dtd + application/xml-dtd + + + dv + video/x-dv + + + dvi + application/x-dvi + + + eps + application/postscript + + + etx + text/x-setext + + + exe + application/octet-stream + + + gif + image/gif + + + gtar + application/x-gtar + + + gz + application/x-gzip + + + hdf + application/x-hdf + + + hqx + application/mac-binhex40 + + + htc + text/x-component + + + htm + text/html + + + html + text/html + + + hqx + application/mac-binhex40 + + + ief + image/ief + + + jad + text/vnd.sun.j2me.app-descriptor + + + jar + application/java-archive + + + java + text/plain + + + jnlp + application/x-java-jnlp-file + + + jpe + image/jpeg + + + jpeg + image/jpeg + + + jpg + image/jpeg + + + js + text/javascript + + + jsf + text/plain + + + jspf + text/plain + + + kar + audio/x-midi + + + latex + application/x-latex + + + m3u + audio/x-mpegurl + + + mac + image/x-macpaint + + + man + application/x-troff-man + + + mathml + application/mathml+xml + + + me + application/x-troff-me + + + mid + audio/x-midi + + + midi + audio/x-midi + + + mif + application/x-mif + + + mov + video/quicktime + + + movie + video/x-sgi-movie + + + mp1 + audio/x-mpeg + + + mp2 + audio/x-mpeg + + + mp3 + audio/x-mpeg + + + mp4 + video/mp4 + + + mpa + audio/x-mpeg + + + mpe + video/mpeg + + + mpeg + video/mpeg + + + mpega + audio/x-mpeg + + + mpg + video/mpeg + + + mpv2 + video/mpeg2 + + + ms + application/x-wais-source + + + nc + application/x-netcdf + + + oda + application/oda + + + + odb + application/vnd.oasis.opendocument.database + + + + odc + application/vnd.oasis.opendocument.chart + + + + odf + application/vnd.oasis.opendocument.formula + + + + odg + application/vnd.oasis.opendocument.graphics + + + + odi + application/vnd.oasis.opendocument.image + + + + odm + application/vnd.oasis.opendocument.text-master + + + + odp + application/vnd.oasis.opendocument.presentation + + + + ods + application/vnd.oasis.opendocument.spreadsheet + + + + odt + application/vnd.oasis.opendocument.text + + + ogg + application/ogg + + + + otg + application/vnd.oasis.opendocument.graphics-template + + + + oth + application/vnd.oasis.opendocument.text-web + + + + otp + application/vnd.oasis.opendocument.presentation-template + + + + ots + application/vnd.oasis.opendocument.spreadsheet-template + + + + ott + application/vnd.oasis.opendocument.text-template + + + pbm + image/x-portable-bitmap + + + pct + image/pict + + + pdf + application/pdf + + + pgm + image/x-portable-graymap + + + pic + image/pict + + + pict + image/pict + + + pls + audio/x-scpls + + + png + image/png + + + pnm + image/x-portable-anymap + + + pnt + image/x-macpaint + + + ppm + image/x-portable-pixmap + + + ppt + application/vnd.ms-powerpoint + + + pps + application/vnd.ms-powerpoint + + + ps + application/postscript + + + psd + image/x-photoshop + + + qt + video/quicktime + + + qti + image/x-quicktime + + + qtif + image/x-quicktime + + + ras + image/x-cmu-raster + + + rdf + application/rdf+xml + + + rgb + image/x-rgb + + + rm + application/vnd.rn-realmedia + + + roff + application/x-troff + + + rtf + application/rtf + + + rtx + text/richtext + + + sh + application/x-sh + + + shar + application/x-shar + + + + smf + audio/x-midi + + + sit + application/x-stuffit + + + snd + audio/basic + + + src + application/x-wais-source + + + sv4cpio + application/x-sv4cpio + + + sv4crc + application/x-sv4crc + + + svg + image/svg+xml + + + svgz + image/svg+xml + + + swf + application/x-shockwave-flash + + + t + application/x-troff + + + tar + application/x-tar + + + tcl + application/x-tcl + + + tex + application/x-tex + + + texi + application/x-texinfo + + + texinfo + application/x-texinfo + + + tif + image/tiff + + + tiff + image/tiff + + + tr + application/x-troff + + + tsv + text/tab-separated-values + + + txt + text/plain + + + ulw + audio/basic + + + ustar + application/x-ustar + + + vxml + application/voicexml+xml + + + xbm + image/x-xbitmap + + + xht + application/xhtml+xml + + + xhtml + application/xhtml+xml + + + xls + application/vnd.ms-excel + + + xml + application/xml + + + xpm + image/x-xpixmap + + + xsl + application/xml + + + xslt + application/xslt+xml + + + xul + application/vnd.mozilla.xul+xml + + + xwd + image/x-xwindowdump + + + vsd + application/x-visio + + + wav + audio/x-wav + + + + wbmp + image/vnd.wap.wbmp + + + + wml + text/vnd.wap.wml + + + + wmlc + application/vnd.wap.wmlc + + + + wmls + text/vnd.wap.wmlscript + + + + wmlscriptc + application/vnd.wap.wmlscriptc + + + wmv + video/x-ms-wmv + + + wrl + x-world/x-vrml + + + wspolicy + application/wspolicy+xml + + + Z + application/x-compress + + + z + application/x-compress + + + zip + application/zip + + + + + + + + + + + + + + + + index.html + index.htm + index.jsp + + + diff --git a/awsapi/.project b/awsapi/.project index 8bce14ddc45..d602ee44c58 100644 --- a/awsapi/.project +++ b/awsapi/.project @@ -1,17 +1,23 @@ - - - awsapi - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - + + + awsapi + + + + + + org.python.pydev.PyDevBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + org.python.pydev.pythonNature + + diff --git a/awsapi/.pydevproject b/awsapi/.pydevproject new file mode 100644 index 00000000000..a9cca037b33 --- /dev/null +++ b/awsapi/.pydevproject @@ -0,0 +1,7 @@ + + + + +Default +python 2.7 + diff --git a/awsapi/LICENSE.txt b/awsapi/LICENSE.txt new file mode 100644 index 00000000000..6b0b1270ff0 --- /dev/null +++ b/awsapi/LICENSE.txt @@ -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. + diff --git a/awsapi/NOTICE.txt b/awsapi/NOTICE.txt new file mode 100644 index 00000000000..bd396930715 --- /dev/null +++ b/awsapi/NOTICE.txt @@ -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, . + +Please read the different LICENSE files present in the lib directory of +this distribution. diff --git a/awsapi/README.txt b/awsapi/README.txt new file mode 100644 index 00000000000..99788bf81e1 --- /dev/null +++ b/awsapi/README.txt @@ -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://:/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. diff --git a/awsapi/axis2.war b/awsapi/axis2.war new file mode 100644 index 00000000000..af46ab55990 Binary files /dev/null and b/awsapi/axis2.war differ diff --git a/awsapi/conf/cloud-bridge.properties b/awsapi/conf/cloud-bridge.properties index e3d815559d8..0c2b23c79df 100644 --- a/awsapi/conf/cloud-bridge.properties +++ b/awsapi/conf/cloud-bridge.properties @@ -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! diff --git a/awsapi/conf/ec2-service.properties b/awsapi/conf/ec2-service.properties index fc3329b3dd5..29c1d738712 100644 --- a/awsapi/conf/ec2-service.properties +++ b/awsapi/conf/ec2-service.properties @@ -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! diff --git a/awsapi/conf/hibernate.cfg.xml b/awsapi/conf/hibernate.cfg.xml index e87bee587f9..a0f0e28a6d0 100644 --- a/awsapi/conf/hibernate.cfg.xml +++ b/awsapi/conf/hibernate.cfg.xml @@ -4,6 +4,12 @@ com.mysql.jdbc.Driver +<<<<<<< HEAD +======= + jdbc:mysql://localhost/cloudbridge + cloud + cloud +>>>>>>> 6472e7b... Now really adding the renamed files! 20 false @@ -16,10 +22,17 @@ true +<<<<<<< HEAD +======= + +>>>>>>> 6472e7b... Now really adding the renamed files! diff --git a/awsapi/conf/log4j-cloud-bridge.xml b/awsapi/conf/log4j-cloud-bridge.xml new file mode 100644 index 00000000000..cc5a76f6de2 --- /dev/null +++ b/awsapi/conf/log4j-cloud-bridge.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/awsapi/docs/AmazonS3/wsdl2java-command-line.txt b/awsapi/docs/AmazonS3/wsdl2java-command-line.txt new file mode 100644 index 00000000000..fbd134075b1 --- /dev/null +++ b/awsapi/docs/AmazonS3/wsdl2java-command-line.txt @@ -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 diff --git a/awsapi/modules/axis2-adb-1.6.2.jar b/awsapi/modules/axis2-adb-1.6.2.jar new file mode 100644 index 00000000000..6234fdbba89 Binary files /dev/null and b/awsapi/modules/axis2-adb-1.6.2.jar differ diff --git a/awsapi/modules/axis2-adb-codegen-1.6.2.jar b/awsapi/modules/axis2-adb-codegen-1.6.2.jar new file mode 100644 index 00000000000..7d037d49846 Binary files /dev/null and b/awsapi/modules/axis2-adb-codegen-1.6.2.jar differ diff --git a/awsapi/modules/axis2-ant-plugin-1.6.2.jar b/awsapi/modules/axis2-ant-plugin-1.6.2.jar new file mode 100644 index 00000000000..771b2222319 Binary files /dev/null and b/awsapi/modules/axis2-ant-plugin-1.6.2.jar differ diff --git a/awsapi/modules/axis2-clustering-1.6.2.jar b/awsapi/modules/axis2-clustering-1.6.2.jar new file mode 100644 index 00000000000..e45be9997e0 Binary files /dev/null and b/awsapi/modules/axis2-clustering-1.6.2.jar differ diff --git a/awsapi/modules/axis2-codegen-1.6.2.jar b/awsapi/modules/axis2-codegen-1.6.2.jar new file mode 100644 index 00000000000..f742f19c6b7 Binary files /dev/null and b/awsapi/modules/axis2-codegen-1.6.2.jar differ diff --git a/awsapi/modules/axis2-corba-1.6.2.jar b/awsapi/modules/axis2-corba-1.6.2.jar new file mode 100644 index 00000000000..ee3c78e9ddf Binary files /dev/null and b/awsapi/modules/axis2-corba-1.6.2.jar differ diff --git a/awsapi/modules/axis2-fastinfoset-1.6.2.jar b/awsapi/modules/axis2-fastinfoset-1.6.2.jar new file mode 100644 index 00000000000..d10c36a4926 Binary files /dev/null and b/awsapi/modules/axis2-fastinfoset-1.6.2.jar differ diff --git a/awsapi/modules/axis2-java2wsdl-1.6.2.jar b/awsapi/modules/axis2-java2wsdl-1.6.2.jar new file mode 100644 index 00000000000..0bb869d71f1 Binary files /dev/null and b/awsapi/modules/axis2-java2wsdl-1.6.2.jar differ diff --git a/awsapi/modules/axis2-jaxbri-1.6.2.jar b/awsapi/modules/axis2-jaxbri-1.6.2.jar new file mode 100644 index 00000000000..616eec9ca65 Binary files /dev/null and b/awsapi/modules/axis2-jaxbri-1.6.2.jar differ diff --git a/awsapi/modules/axis2-jaxws-1.6.2.jar b/awsapi/modules/axis2-jaxws-1.6.2.jar new file mode 100644 index 00000000000..064351a5b8a Binary files /dev/null and b/awsapi/modules/axis2-jaxws-1.6.2.jar differ diff --git a/awsapi/modules/axis2-jibx-1.6.2.jar b/awsapi/modules/axis2-jibx-1.6.2.jar new file mode 100644 index 00000000000..75f9d1a4c5b Binary files /dev/null and b/awsapi/modules/axis2-jibx-1.6.2.jar differ diff --git a/awsapi/modules/axis2-json-1.6.2.jar b/awsapi/modules/axis2-json-1.6.2.jar new file mode 100644 index 00000000000..edd79368eaa Binary files /dev/null and b/awsapi/modules/axis2-json-1.6.2.jar differ diff --git a/awsapi/modules/axis2-kernel-1.6.2.jar b/awsapi/modules/axis2-kernel-1.6.2.jar new file mode 100644 index 00000000000..3ae5f7a0466 Binary files /dev/null and b/awsapi/modules/axis2-kernel-1.6.2.jar differ diff --git a/awsapi/modules/axis2-metadata-1.6.2.jar b/awsapi/modules/axis2-metadata-1.6.2.jar new file mode 100644 index 00000000000..492f1ac4ab7 Binary files /dev/null and b/awsapi/modules/axis2-metadata-1.6.2.jar differ diff --git a/awsapi/modules/axis2-mtompolicy-1.6.2.jar b/awsapi/modules/axis2-mtompolicy-1.6.2.jar new file mode 100644 index 00000000000..561e84a9536 Binary files /dev/null and b/awsapi/modules/axis2-mtompolicy-1.6.2.jar differ diff --git a/awsapi/modules/axis2-saaj-1.6.2.jar b/awsapi/modules/axis2-saaj-1.6.2.jar new file mode 100644 index 00000000000..c14531dc563 Binary files /dev/null and b/awsapi/modules/axis2-saaj-1.6.2.jar differ diff --git a/awsapi/modules/axis2-soapmonitor-servlet-1.6.2.jar b/awsapi/modules/axis2-soapmonitor-servlet-1.6.2.jar new file mode 100644 index 00000000000..276dac7e76c Binary files /dev/null and b/awsapi/modules/axis2-soapmonitor-servlet-1.6.2.jar differ diff --git a/awsapi/modules/axis2-spring-1.6.2.jar b/awsapi/modules/axis2-spring-1.6.2.jar new file mode 100644 index 00000000000..30b9baaffd5 Binary files /dev/null and b/awsapi/modules/axis2-spring-1.6.2.jar differ diff --git a/awsapi/modules/axis2-transport-http-1.6.2.jar b/awsapi/modules/axis2-transport-http-1.6.2.jar new file mode 100644 index 00000000000..b1dad789900 Binary files /dev/null and b/awsapi/modules/axis2-transport-http-1.6.2.jar differ diff --git a/awsapi/modules/axis2-transport-local-1.6.2.jar b/awsapi/modules/axis2-transport-local-1.6.2.jar new file mode 100644 index 00000000000..34a7073f34f Binary files /dev/null and b/awsapi/modules/axis2-transport-local-1.6.2.jar differ diff --git a/awsapi/modules/axis2-xmlbeans-1.6.2.jar b/awsapi/modules/axis2-xmlbeans-1.6.2.jar new file mode 100644 index 00000000000..58fba9b9bed Binary files /dev/null and b/awsapi/modules/axis2-xmlbeans-1.6.2.jar differ diff --git a/awsapi/release-notes.html b/awsapi/release-notes.html new file mode 100644 index 00000000000..419cb188d32 --- /dev/null +++ b/awsapi/release-notes.html @@ -0,0 +1,123 @@ + + + + + + Welcome to Apache Axis2 version 1.6.2 + + + +

Welcome to Apache Axis2 version 1.6.2

+ +

April 17, 2012

+ +
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 here.
+
+
+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 Axis2 Transports 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
+   
+    
+ + diff --git a/awsapi/release-notes.txt b/awsapi/release-notes.txt index 04250ec0b42..6b20c73a754 100644 --- a/awsapi/release-notes.txt +++ b/awsapi/release-notes.txt @@ -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 ========= diff --git a/awsapi/src/com/cloud/bridge/auth/s3/AuthenticationHandler.java b/awsapi/src/com/cloud/bridge/auth/s3/AuthenticationHandler.java index 3b2ffcb282f..e1eb06347be 100644 --- a/awsapi/src/com/cloud/bridge/auth/s3/AuthenticationHandler.java +++ b/awsapi/src/com/cloud/bridge/auth/s3/AuthenticationHandler.java @@ -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); diff --git a/awsapi/src/com/cloud/bridge/io/DimeDelimitedInputStream.java b/awsapi/src/com/cloud/bridge/io/DimeDelimitedInputStream.java new file mode 100644 index 00000000000..bad5164127d --- /dev/null +++ b/awsapi/src/com/cloud/bridge/io/DimeDelimitedInputStream.java @@ -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 +
+ 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                         /
+ /                                                               |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ * 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 InputStream 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; + } + } +} + diff --git a/awsapi/src/com/cloud/bridge/io/FileRangeDataSource.java b/awsapi/src/com/cloud/bridge/io/FileRangeDataSource.java new file mode 100644 index 00000000000..d87d5d39926 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/io/FileRangeDataSource.java @@ -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; + } +} diff --git a/awsapi/src/com/cloud/bridge/io/FileRangeInputStream.java b/awsapi/src/com/cloud/bridge/io/FileRangeInputStream.java new file mode 100644 index 00000000000..4fb87e2ee42 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/io/FileRangeInputStream.java @@ -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(); + } +} diff --git a/awsapi/src/com/cloud/bridge/io/MTOMAwareResultStreamWriter.java b/awsapi/src/com/cloud/bridge/io/MTOMAwareResultStreamWriter.java new file mode 100644 index 00000000000..6c6fc24bc34 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/io/MTOMAwareResultStreamWriter.java @@ -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 = ""; + 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); + } + + } + + diff --git a/awsapi/src/com/cloud/bridge/io/MultiPartDimeInputStream.java b/awsapi/src/com/cloud/bridge/io/MultiPartDimeInputStream.java new file mode 100644 index 00000000000..219f6989db1 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/io/MultiPartDimeInputStream.java @@ -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; + } +} + diff --git a/awsapi/src/com/cloud/bridge/io/S3FileSystemBucketAdapter.java b/awsapi/src/com/cloud/bridge/io/S3FileSystemBucketAdapter.java new file mode 100644 index 00000000000..7cc45042efc --- /dev/null +++ b/awsapi/src/com/cloud/bridge/io/S3FileSystemBucketAdapter.java @@ -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 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(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; + } +} diff --git a/awsapi/src/com/cloud/bridge/lifecycle/ServiceEngineLifecycle.java b/awsapi/src/com/cloud/bridge/lifecycle/ServiceEngineLifecycle.java index e34eb15cfa9..889a3e76c81 100644 --- a/awsapi/src/com/cloud/bridge/lifecycle/ServiceEngineLifecycle.java +++ b/awsapi/src/com/cloud/bridge/lifecycle/ServiceEngineLifecycle.java @@ -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 diff --git a/awsapi/src/com/cloud/bridge/model/SAcl.java b/awsapi/src/com/cloud/bridge/model/SAcl.java index 119d1a124f3..e94fdcfce16 100644 --- a/awsapi/src/com/cloud/bridge/model/SAcl.java +++ b/awsapi/src/com/cloud/bridge/model/SAcl.java @@ -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 getCannedAccessControls ( String aclRequestString, String target ) + throws UnsupportedException + { + if ( aclRequestString.equalsIgnoreCase( "public-read" )) + // All users granted READ access. + return new OrderedPair (PERMISSION_READ,GRANTEE_ALLUSERS); + else if (aclRequestString.equalsIgnoreCase( "public-read-write" )) + // All users granted READ and WRITE access + return new OrderedPair ((PERMISSION_READ | PERMISSION_WRITE),GRANTEE_ALLUSERS); + else if (aclRequestString.equalsIgnoreCase( "authenticated-read" )) + // Authenticated users have READ access + return new OrderedPair (PERMISSION_READ,GRANTEE_AUTHENTICATED); + else if (aclRequestString.equalsIgnoreCase( "private" )) + // Only Owner gets FULL_CONTROL + return new OrderedPair (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 (PERMISSION_READ, GRANTEE_USER); + else + return new OrderedPair (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 (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 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 (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 (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 (PERMISSION_FULL, PERMISSION_READ,"*"); + else if (aclRequestString.equalsIgnoreCase( "private" )) + // This is termed the "private" or default ACL, "Owner gets FULL_CONTROL" + return new Triple (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 (PERMISSION_FULL,PERMISSION_FULL ,null); + else + return new Triple (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 (PERMISSION_FULL, PERMISSION_FULL, null); + else + return new Triple (PERMISSION_FULL,PERMISSION_FULL, ownerID); + } + else throw new UnsupportedException( "Unknown Canned Access Policy: " + aclRequestString + " is not supported" ); + } + +>>>>>>> 6472e7b... Now really adding the renamed files! } diff --git a/awsapi/src/com/cloud/bridge/model/SBucket.java b/awsapi/src/com/cloud/bridge/model/SBucket.java index 983fde0d1cb..12e5d73e21f 100644 --- a/awsapi/src/com/cloud/bridge/model/SBucket.java +++ b/awsapi/src/com/cloud/bridge/model/SBucket.java @@ -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; diff --git a/awsapi/src/com/cloud/bridge/model/SHost.java b/awsapi/src/com/cloud/bridge/model/SHost.java index e76cf948844..d055c2d76bb 100644 --- a/awsapi/src/com/cloud/bridge/model/SHost.java +++ b/awsapi/src/com/cloud/bridge/model/SHost.java @@ -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; diff --git a/awsapi/src/com/cloud/bridge/model/SObject.java b/awsapi/src/com/cloud/bridge/model/SObject.java index 785ebba5397..7ded7582f46 100644 --- a/awsapi/src/com/cloud/bridge/model/SObject.java +++ b/awsapi/src/com/cloud/bridge/model/SObject.java @@ -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 { diff --git a/awsapi/src/com/cloud/bridge/model/SObjectItem.java b/awsapi/src/com/cloud/bridge/model/SObjectItem.java index 64c1dd585c8..1f5a82011ca 100644 --- a/awsapi/src/com/cloud/bridge/model/SObjectItem.java +++ b/awsapi/src/com/cloud/bridge/model/SObjectItem.java @@ -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() { diff --git a/awsapi/src/com/cloud/bridge/model/UserCredentials.java b/awsapi/src/com/cloud/bridge/model/UserCredentials.java index 932c7132c03..1f3ad121221 100644 --- a/awsapi/src/com/cloud/bridge/model/UserCredentials.java +++ b/awsapi/src/com/cloud/bridge/model/UserCredentials.java @@ -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(); diff --git a/awsapi/src/com/cloud/bridge/persist/EntityDao.java b/awsapi/src/com/cloud/bridge/persist/EntityDao.java index ba19cceb5fd..ac542b5fad7 100644 --- a/awsapi/src/com/cloud/bridge/persist/EntityDao.java +++ b/awsapi/src/com/cloud/bridge/persist/EntityDao.java @@ -24,6 +24,7 @@ import org.hibernate.Session; import com.cloud.bridge.util.QueryHelper; /** +<<<<<<< HEAD * @author Kelven Yang */ public class EntityDao { @@ -40,33 +41,72 @@ public class EntityDao { 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 { + 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 { } public List 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 { } public List 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 { } 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); diff --git a/awsapi/src/com/cloud/bridge/persist/PersistContext.java b/awsapi/src/com/cloud/bridge/persist/PersistContext.java index e721a1ddd2f..0674ed388b0 100644 --- a/awsapi/src/com/cloud/bridge/persist/PersistContext.java +++ b/awsapi/src/com/cloud/bridge/persist/PersistContext.java @@ -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 threadSession = new ThreadLocal(); private static final ThreadLocal threadTransaction = new ThreadLocal(); private static final ThreadLocal> threadStore = new ThreadLocal>(); +<<<<<<< HEAD private static final CloudStackSessionFactory cloudStackSessionFactory; private static final ThreadLocal threadCloudStackSession = new ThreadLocal(); private static final ThreadLocal threadCloudStackTransaction = new ThreadLocal(); @@ -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 info = (Tuple)getThreadStoreObject(registryKey); +======= + OrderedPair info = (OrderedPair)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)); +======= + registerThreadStoreObject(registryKey, new OrderedPair(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 info = (Tuple)unregisterThreadStoreObject(registryKey); +======= + OrderedPair info = (OrderedPair)unregisterThreadStoreObject(registryKey); +>>>>>>> 6472e7b... Now really adding the renamed files! if(info != null) { try { info.getSecond().close(); diff --git a/awsapi/src/com/cloud/bridge/persist/dao/BucketPolicyDao.java b/awsapi/src/com/cloud/bridge/persist/dao/BucketPolicyDao.java index acd441e3b73..2240412e3ab 100644 --- a/awsapi/src/com/cloud/bridge/persist/dao/BucketPolicyDao.java +++ b/awsapi/src/com/cloud/bridge/persist/dao/BucketPolicyDao.java @@ -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! } } diff --git a/awsapi/src/com/cloud/bridge/persist/dao/MultipartLoadDao.java b/awsapi/src/com/cloud/bridge/persist/dao/MultipartLoadDao.java index 9f144798c7f..6c6b1e0404f 100644 --- a/awsapi/src/com/cloud/bridge/persist/dao/MultipartLoadDao.java +++ b/awsapi/src/com/cloud/bridge/persist/dao/MultipartLoadDao.java @@ -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 multipartExits( int uploadId ) +======= + public OrderedPair 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( accessKey, nameKey ); +======= + return new OrderedPair( 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 * @throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException */ public Tuple getInitiatedUploads( String bucketName, int maxParts, String prefix, String keyMarker, String uploadIdMarker ) +======= + * @return OrderedPair + * @throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException + */ + public OrderedPair 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(inProgress, isTruncated); +======= + return new OrderedPair(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! } } diff --git a/awsapi/src/com/cloud/bridge/persist/dao/OfferingDao.java b/awsapi/src/com/cloud/bridge/persist/dao/OfferingDao.java index c8433cfd376..73b508b4479 100644 --- a/awsapi/src/com/cloud/bridge/persist/dao/OfferingDao.java +++ b/awsapi/src/com/cloud/bridge/persist/dao/OfferingDao.java @@ -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! } } diff --git a/awsapi/src/com/cloud/bridge/persist/dao/SMetaDao.java b/awsapi/src/com/cloud/bridge/persist/dao/SMetaDao.java index c5b7313cdc1..50adf07867a 100644 --- a/awsapi/src/com/cloud/bridge/persist/dao/SMetaDao.java +++ b/awsapi/src/com/cloud/bridge/persist/dao/SMetaDao.java @@ -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 { public SMetaDao() { @@ -46,7 +50,11 @@ public class SMetaDao extends EntityDao { } 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) { diff --git a/awsapi/src/com/cloud/bridge/persist/dao/UserCredentialsDao.java b/awsapi/src/com/cloud/bridge/persist/dao/UserCredentialsDao.java index d968cd3dc59..f20d56200ee 100644 --- a/awsapi/src/com/cloud/bridge/persist/dao/UserCredentialsDao.java +++ b/awsapi/src/com/cloud/bridge/persist/dao/UserCredentialsDao.java @@ -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! } } diff --git a/awsapi/src/com/cloud/bridge/service/EC2MainServlet.java b/awsapi/src/com/cloud/bridge/service/EC2MainServlet.java index 8c938812942..3b2fea71169 100644 --- a/awsapi/src/com/cloud/bridge/service/EC2MainServlet.java +++ b/awsapi/src/com/cloud/bridge/service/EC2MainServlet.java @@ -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); diff --git a/awsapi/src/com/cloud/bridge/service/EC2RestServlet.java b/awsapi/src/com/cloud/bridge/service/EC2RestServlet.java index b8d639b6fd5..5abdf603dcc 100644 --- a/awsapi/src/com/cloud/bridge/service/EC2RestServlet.java +++ b/awsapi/src/com/cloud/bridge/service/EC2RestServlet.java @@ -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( "" + version + "" ); response.setStatus(200); endResponse(response, version_response); +======= + String version = new String( "1.03" ); + 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(); diff --git a/awsapi/src/com/cloud/bridge/service/EC2SoapService.java b/awsapi/src/com/cloud/bridge/service/EC2SoapService.java index 00262353baf..6c866030240 100644 --- a/awsapi/src/com/cloud/bridge/service/EC2SoapService.java +++ b/awsapi/src/com/cloud/bridge/service/EC2SoapService.java @@ -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); diff --git a/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java b/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java index 953107fd2f0..2ac3ffc9581 100644 --- a/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java +++ b/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java @@ -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(); diff --git a/awsapi/src/com/cloud/bridge/service/S3Constants.java b/awsapi/src/com/cloud/bridge/service/S3Constants.java index a14fced6287..f8e702a5697 100644 --- a/awsapi/src/com/cloud/bridge/service/S3Constants.java +++ b/awsapi/src/com/cloud/bridge/service/S3Constants.java @@ -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! } diff --git a/awsapi/src/com/cloud/bridge/service/S3RestServlet.java b/awsapi/src/com/cloud/bridge/service/S3RestServlet.java index e7e75c16cfd..e4ec384a111 100644 --- a/awsapi/src/com/cloud/bridge/service/S3RestServlet.java +++ b/awsapi/src/com/cloud/bridge/service/S3RestServlet.java @@ -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( "1.04" ); + 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.append( "\n" ); + xml.append( "\n" ); + xml.append( "\n" ); + xml.append( "" ).append( e.getFaultCode().toString()).append( "\n" ); + xml.append( "" ).append( reason ).append( "\n" ); + xml.append( "\n" ); + xml.append( "" ); + + 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.append( "" ); + xml.append( "" ); + xml.append( "" ); + xml.append( "" ); + xml.append( "\"").append( putResponse.getETag()).append( "\"" ); + xml.append( "").append( DatatypeConverter.printDateTime(putResponse.getLastModified())).append( "" ); + xml.append( "" ); + xml.append( "" ); + + 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! diff --git a/awsapi/src/com/cloud/bridge/service/UserContext.java b/awsapi/src/com/cloud/bridge/service/UserContext.java index 30919915bab..ff5b7d80e93 100644 --- a/awsapi/src/com/cloud/bridge/service/UserContext.java +++ b/awsapi/src/com/cloud/bridge/service/UserContext.java @@ -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; diff --git a/awsapi/src/com/cloud/bridge/service/controller/s3/S3BucketAction.java b/awsapi/src/com/cloud/bridge/service/controller/s3/S3BucketAction.java index b89370d6cb7..0e0d215678c 100644 --- a/awsapi/src/com/cloud/bridge/service/controller/s3/S3BucketAction.java +++ b/awsapi/src/com/cloud/bridge/service/controller/s3/S3BucketAction.java @@ -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.append( "" ); + if (0 < versioningStatus.length()) xml.append( "" ).append( versioningStatus ).append( "" ); + xml.append( "" ); + + 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.append( "" ); + xml.append( "" ).append( engineResponse.getBucketName()).append( "" ); + + if ( null == keyMarker ) + xml.append( "" ); + else xml.append( "" ).append( keyMarker ).append( "" ); + else xml.append( "" ).append( keyMarker ).append( "" ).append( engineResponse.getMaxKeys()).append( "" ); + xml.append( "" ).append( engineResponse.isTruncated()).append( "" ); + + 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( "" ); + xml.append( "" ).append( versions[i].getKey()).append( "" ); + xml.append( "" ).append( versions[i].getVersion()).append( "" ); + xml.append( "" ).append( versions[i].getIsLatest()).append( "" ); + xml.append( "" ).append( DatatypeConverter.printDateTime( versions[i].getLastModified())).append( "" ); + } + else + { xml.append( "" ); + xml.append( "" ).append( versions[i].getKey()).append( "" ); + xml.append( "" ).append( versions[i].getVersion()).append( "" ); + xml.append( "" ).append( versions[i].getIsLatest()).append( "" ); + xml.append( "" ).append( DatatypeConverter.printDateTime( versions[i].getLastModified())).append( "" ); + xml.append( "" ).append( versions[i].getETag()).append( "" ); + xml.append( "" ).append( versions[i].getSize()).append( "" ); + xml.append( "" ).append( versions[i].getStorageClass()).append( "" ); + } + + xml.append( "" ); + xml.append( "" ).append( id ).append( "" ); + if ( null == displayName ) + xml.append( "" ); + else xml.append( "" ).append( owner.getDisplayName()).append( "" ); + xml.append( "" ); + + if ( isDeletionMarker ) + xml.append( "" ); + else xml.append( "" ); + } + xml.append( "" ); + + 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 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 \nAllowOverride FileInfo AuthConfig Limit... 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 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.append( "" ); + xml.append( "" ).append( bucketName ).append( "" ); + xml.append( "").append((null == keyMarker ? "" : keyMarker)).append( "" ); + xml.append( "").append((null == uploadIdMarker ? "" : uploadIdMarker)).append( "" ); + + + // [C] Construct the contents of the 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( "" ); + partsList.append( "" ).append( nextKey ).append( "" ); + partsList.append( "" ).append( nextUploadId ).append( "" ); + partsList.append( "" ); + partsList.append( "" ).append( onePart.getAccessKey()).append( "" ); + partsList.append( "" ); + partsList.append( "" ); + partsList.append( "" ); + partsList.append( "" ).append( onePart.getAccessKey()).append( "" ); + partsList.append( "" ); + partsList.append( "" ); + partsList.append( "STANDARD" ); + partsList.append( "" ).append( DatatypeConverter.printDateTime( onePart.getLastModified())).append( "" ); + partsList.append( "" ); + } + + // [D] Construct the contents of the 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( "" ); + partsList.append( "" ); + if ( prefix != null && prefix.length() > 0 ) + partsList.append( prefix + delimiter + subName ); + else partsList.append( subName ); + partsList.append( "" ); + partsList.append( "" ); + } + } + } + + // [D] Finish off the response + xml.append( "" ).append((null == nextKey ? "" : nextKey)).append( "" ); + xml.append( "" ).append((0 == nextUploadId ? "" : nextUploadId)).append( "" ); + xml.append( "" ).append( maxUploads ).append( "" ); + xml.append( "" ).append( isTruncated ).append( "" ); + + xml.append( partsList.toString()); + xml.append( "" ); + + 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! diff --git a/awsapi/src/com/cloud/bridge/service/controller/s3/S3ObjectAction.java b/awsapi/src/com/cloud/bridge/service/controller/s3/S3ObjectAction.java index 38945d02639..148ed57968a 100644 --- a/awsapi/src/com/cloud/bridge/service/controller/s3/S3ObjectAction.java +++ b/awsapi/src/com/cloud/bridge/service/controller/s3/S3ObjectAction.java @@ -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 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("".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 match = verifyParts( request.getInputStream(), parts ); if (200 != match.getFirst().intValue()) { response.setStatus(match.getFirst().intValue()); returnErrorXML( match.getFirst().intValue(), match.getSecond(), os ); +======= + OrderedPair 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( "" ); +======= + // If all successful then clean up all left over parts + // Notice that "" 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( "" ); xml.append( "" ).append( "http://" + bucket + ".s3.amazonaws.com/" + key ).append( "" ); xml.append( "" ).append( bucket ).append( "" ); xml.append( "" ).append( key ).append( "" ); +<<<<<<< HEAD xml.append( "\"" ).append( engineResponse.getETag()).append( "\"" ); xml.append( "" ); os.write( xml.toString().getBytes()); os.close(); } else returnErrorXML( result, null, os ); +======= + xml.append( "\"" ).append( engineResponse.getETag()).append( "\"" ); + xml.append( "" ); + 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 exists = uploadDao.multipartExits( uploadId ); +======= + OrderedPair 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 verifyParts( InputStream is, S3MultipartPart[] parts ) +======= + private OrderedPair 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(400, "InvalidPart"); +======= + if (count != parts.length) return new OrderedPair(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(400, "InvalidPartOrder"); +======= + return new OrderedPair(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(400, "InvalidPart"); +======= + return new OrderedPair(400, "InvalidPart"); +>>>>>>> 6472e7b... Now really adding the renamed files! } lastNumber = partNumber; } +<<<<<<< HEAD return new Tuple(200, "Success"); } catch( Exception e ) { return new Tuple(500, e.toString()); +======= + return new OrderedPair(200, "Success"); + } + catch( Exception e ) { + return new OrderedPair(500, e.toString()); +>>>>>>> 6472e7b... Now really adding the renamed files! } } } diff --git a/awsapi/src/com/cloud/bridge/service/controller/s3/S3SerializableServiceImplementation.java b/awsapi/src/com/cloud/bridge/service/controller/s3/S3SerializableServiceImplementation.java new file mode 100644 index 00000000000..1c34a783b97 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/service/controller/s3/S3SerializableServiceImplementation.java @@ -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; + } +} diff --git a/awsapi/src/com/cloud/bridge/service/controller/s3/ServiceProvider.java b/awsapi/src/com/cloud/bridge/service/controller/s3/ServiceProvider.java new file mode 100644 index 00000000000..4ddc2678561 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/service/controller/s3/ServiceProvider.java @@ -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 . + * + */ +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, Object> serviceMap = new HashMap, 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 policyMap = new HashMap(); + + 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 getBucketPolicy(String bucketName) { + + if (policyMap.containsKey( bucketName )) { + S3BucketPolicy policy = policyMap.get( bucketName ); + return new OrderedPair( policy, 0 ); + } + else return new OrderedPair( 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 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 getServiceImpl(Class serviceInterface) { + return getProxy(serviceInterface, (T)serviceMap.get(serviceInterface)); + } +} diff --git a/awsapi/src/com/cloud/bridge/service/controller/s3/ServletAction.java b/awsapi/src/com/cloud/bridge/service/controller/s3/ServletAction.java new file mode 100644 index 00000000000..14c898c5f88 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/service/controller/s3/ServletAction.java @@ -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; +} diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java index 80e9bc74217..98859053fb8 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java @@ -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 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 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 result = new ArrayList(); if(templateId != null){ @@ -1749,6 +1852,11 @@ public class EC2Engine { if (result != null && result.size() > 0) { for (CloudStackTemplate temp : result) { +======= + List 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 networks = getApi().listNetworks(caller.getName(), caller.getDomainId(), null, true, null, null, null, null, null, zoneId); @@ -1964,6 +2083,31 @@ public class EC2Engine { } } +======= + + List networks = getApi().listNetworks(null, caller.getDomainId(), null, null, null, null, null, null, null, zoneId); + + List 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()); } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2InstanceFilterSet.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2InstanceFilterSet.java index 8cd697c9b6f..e0793c1b44d 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2InstanceFilterSet.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2InstanceFilterSet.java @@ -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! } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2RegisterImage.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2RegisterImage.java index 2ba12a7f5f6..0671e5ef1ac 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2RegisterImage.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2RegisterImage.java @@ -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! } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Snapshot.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Snapshot.java index a03856d86fa..d93ae3647f5 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Snapshot.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Snapshot.java @@ -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 ) { diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2VolumeFilterSet.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2VolumeFilterSet.java index 7bb2bb4e257..e830f8e8ae7 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2VolumeFilterSet.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2VolumeFilterSet.java @@ -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 ) { diff --git a/awsapi/src/com/cloud/bridge/service/core/s3/S3AccessControlList.java b/awsapi/src/com/cloud/bridge/service/core/s3/S3AccessControlList.java index 076d01cc055..c8df391941b 100644 --- a/awsapi/src/com/cloud/bridge/service/core/s3/S3AccessControlList.java +++ b/awsapi/src/com/cloud/bridge/service/core/s3/S3AccessControlList.java @@ -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 list = new ArrayList(); diff --git a/awsapi/src/com/cloud/bridge/service/core/s3/S3BucketAdapter.java b/awsapi/src/com/cloud/bridge/service/core/s3/S3BucketAdapter.java new file mode 100644 index 00000000000..0900a03c3f6 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/service/core/s3/S3BucketAdapter.java @@ -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 concatentateObjects(String mountedRoot, String destBucket, String fileName, String sourceBucket, S3MultipartPart[] parts, OutputStream os); +} diff --git a/awsapi/src/com/cloud/bridge/service/core/s3/S3Engine.java b/awsapi/src/com/cloud/bridge/service/core/s3/S3Engine.java index 5f0e6779318..2509e40c6ba 100644 --- a/awsapi/src/com/cloud/bridge/service/core/s3/S3Engine.java +++ b/awsapi/src/com/cloud/bridge/service/core/s3/S3Engine.java @@ -39,6 +39,10 @@ import org.hibernate.LockMode; import org.hibernate.Session; import org.json.simple.parser.ParseException; +<<<<<<< HEAD +======= +import com.cloud.bridge.io.S3FileSystemBucketAdapter; +>>>>>>> 6472e7b... Now really adding the renamed files! import com.cloud.bridge.model.MHost; import com.cloud.bridge.model.MHostMount; import com.cloud.bridge.model.SAcl; @@ -58,10 +62,16 @@ import com.cloud.bridge.persist.dao.SHostDao; import com.cloud.bridge.persist.dao.SMetaDao; import com.cloud.bridge.persist.dao.SObjectDao; import com.cloud.bridge.persist.dao.SObjectItemDao; +<<<<<<< HEAD import com.cloud.bridge.service.S3BucketAdapter; import com.cloud.bridge.service.S3FileSystemBucketAdapter; import com.cloud.bridge.service.ServiceProvider; import com.cloud.bridge.service.UserContext; +======= +import com.cloud.bridge.service.S3Constants; +import com.cloud.bridge.service.UserContext; +import com.cloud.bridge.service.controller.s3.ServiceProvider; +>>>>>>> 6472e7b... Now really adding the renamed files! import com.cloud.bridge.service.core.s3.S3BucketPolicy.PolicyAccess; import com.cloud.bridge.service.core.s3.S3CopyObjectRequest.MetadataDirective; import com.cloud.bridge.service.core.s3.S3PolicyAction.PolicyActions; @@ -78,10 +88,19 @@ import com.cloud.bridge.service.exception.UnsupportedException; import com.cloud.bridge.util.DateHelper; import com.cloud.bridge.util.PolicyParser; import com.cloud.bridge.util.StringHelper; +<<<<<<< HEAD import com.cloud.bridge.util.Tuple; /** * @author Kelven Yang +======= +import com.cloud.bridge.util.OrderedPair; +import com.cloud.bridge.util.Triple; + +/** + * @author Kelven Yang, John Zucker + * The CRUD control actions to be invoked from S3BucketAction or S3ObjectAction. +>>>>>>> 6472e7b... Now really adding the renamed files! */ public class S3Engine { protected final static Logger logger = Logger.getLogger(S3Engine.class); @@ -94,9 +113,20 @@ public class S3Engine { bucketAdapters.put(SHost.STORAGE_HOST_TYPE_LOCAL, new S3FileSystemBucketAdapter()); } +<<<<<<< HEAD /** * We treat this simply as first a get and then a put of the object the user wants to copy. */ +======= + + /** + * Return a S3CopyObjectResponse which represents an object being copied from source + * to destination bucket. + * Called from S3ObjectAction when copying an object. + * This can be treated as first a GET followed by a PUT of the object the user wants to copy. + */ + +>>>>>>> 6472e7b... Now really adding the renamed files! public S3CopyObjectResponse handleRequest(S3CopyObjectRequest request) { S3CopyObjectResponse response = new S3CopyObjectResponse(); @@ -172,7 +202,11 @@ public class S3Engine { if (PersistContext.acquireNamedLock("bucket.creation", LOCK_ACQUIRING_TIMEOUT_SECONDS)) { +<<<<<<< HEAD Tuple shostTuple = null; +======= + OrderedPair shost_storagelocation_pair = null; +>>>>>>> 6472e7b... Now really adding the renamed files! boolean success = false; try { SBucketDao bucketDao = new SBucketDao(); @@ -181,14 +215,23 @@ public class S3Engine { if (bucketDao.getByName(request.getBucketName()) != null) throw new ObjectAlreadyExistsException("Bucket already exists"); +<<<<<<< HEAD shostTuple = allocBucketStorageHost(request.getBucketName(), null); +======= + shost_storagelocation_pair = allocBucketStorageHost(request.getBucketName(), null); +>>>>>>> 6472e7b... Now really adding the renamed files! SBucket sbucket = new SBucket(); sbucket.setName(request.getBucketName()); sbucket.setCreateTime(DateHelper.currentGMTTime()); sbucket.setOwnerCanonicalId( UserContext.current().getCanonicalUserId()); +<<<<<<< HEAD sbucket.setShost(shostTuple.getFirst()); shostTuple.getFirst().getBuckets().add(sbucket); +======= + sbucket.setShost(shost_storagelocation_pair.getFirst()); + shost_storagelocation_pair.getFirst().getBuckets().add(sbucket); +>>>>>>> 6472e7b... Now really adding the renamed files! bucketDao.save(sbucket); S3AccessControlList acl = request.getAcl(); @@ -205,9 +248,15 @@ public class S3Engine { } finally { +<<<<<<< HEAD if(!success && shostTuple != null) { S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter(shostTuple.getFirst()); bucketAdapter.deleteContainer(shostTuple.getSecond(), request.getBucketName()); +======= + if(!success && shost_storagelocation_pair != null) { + S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter(shost_storagelocation_pair.getFirst()); + bucketAdapter.deleteContainer(shost_storagelocation_pair.getSecond(), request.getBucketName()); +>>>>>>> 6472e7b... Now really adding the renamed files! } PersistContext.releaseNamedLock("bucket.creation"); } @@ -219,6 +268,14 @@ public class S3Engine { return response; } +<<<<<<< HEAD +======= + /** + * Return a S3Response which represents the effect of an object being deleted from its bucket. + * Called from S3BucketAction when deleting an object. + */ + +>>>>>>> 6472e7b... Now really adding the renamed files! public S3Response handleRequest( S3DeleteBucketRequest request ) { S3Response response = new S3Response(); @@ -229,9 +286,16 @@ public class S3Engine { if ( sbucket != null ) { S3PolicyContext context = new S3PolicyContext( PolicyActions.DeleteBucket, bucketName ); +<<<<<<< HEAD switch( verifyPolicy( context )) { case ALLOW: // -> bucket policy can give users permission to delete a bucket while ACLs cannot +======= + switch( verifyPolicy( context )) + { + case ALLOW: + // The bucket policy can give users permission to delete a bucket whereas ACLs cannot +>>>>>>> 6472e7b... Now really adding the renamed files! break; case DENY: @@ -239,7 +303,11 @@ public class S3Engine { case DEFAULT_DENY: default: +<<<<<<< HEAD // -> does not matter what the ACLs say only the owner can delete a bucket +======= + // Irrespective of what the ACLs say, only the owner can delete a bucket +>>>>>>> 6472e7b... Now really adding the renamed files! String client = UserContext.current().getCanonicalUserId(); if (!client.equals( sbucket.getOwnerCanonicalId())) { throw new PermissionDeniedException( "Access Denied - only the owner can delete a bucket" ); @@ -248,6 +316,7 @@ public class S3Engine { } +<<<<<<< HEAD // -> delete the file Tuple tupleBucketHost = getBucketStorageHost(sbucket); S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter(tupleBucketHost.getFirst()); @@ -258,11 +327,29 @@ public class S3Engine { // Delete SMeta & SAcl objects: (1)Get all the objects in the bucket, (2)then all the items in each object, (3) then all meta & acl data for each item Set objectsInBucket = sbucket.getObjectsInBucket(); Iterator it = objectsInBucket.iterator(); +======= + // Delete the file from its storage location + OrderedPair host_storagelocation_pair = getBucketStorageHost(sbucket); + S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter(host_storagelocation_pair.getFirst()); + bucketAdapter.deleteContainer(host_storagelocation_pair.getSecond(), request.getBucketName()); + + // Cascade-deleting can delete related SObject/SObjectItem objects, but not SAcl, SMeta and policy objects. + // To delete SMeta & SAcl objects: + // (1)Get all the objects in the bucket, + // (2)then all the items in each object, + // (3) then all meta & acl data for each item + Set objectsInBucket = sbucket.getObjectsInBucket(); + Iterator it = objectsInBucket.iterator(); +>>>>>>> 6472e7b... Now really adding the renamed files! while( it.hasNext()) { SObject oneObject = (SObject)it.next(); Set itemsInObject = oneObject.getItems(); +<<<<<<< HEAD Iterator is = itemsInObject.iterator(); +======= + Iterator is = itemsInObject.iterator(); +>>>>>>> 6472e7b... Now really adding the renamed files! while( is.hasNext()) { SObjectItem oneItem = (SObjectItem)is.next(); @@ -271,7 +358,11 @@ public class S3Engine { } } +<<<<<<< HEAD // -> delete all the policy state associated with the bucket +======= + // Delete all the policy state associated with the bucket +>>>>>>> 6472e7b... Now really adding the renamed files! try { ServiceProvider.getInstance().deleteBucketPolicy( bucketName ); BucketPolicyDao policyDao = new BucketPolicyDao(); @@ -293,6 +384,14 @@ public class S3Engine { return response; } +<<<<<<< HEAD +======= + /** + * Return a S3ListBucketResponse which represents a list of up to 1000 objects contained ins the bucket. + * Called from S3BucketAction for GETting objects and for GETting object versions. + */ + +>>>>>>> 6472e7b... Now really adding the renamed files! public S3ListBucketResponse listBucketContents(S3ListBucketRequest request, boolean includeVersions) { S3ListBucketResponse response = new S3ListBucketResponse(); @@ -318,7 +417,11 @@ public class S3Engine { verifyAccess( context, "SBucket", sbucket.getId(), SAcl.PERMISSION_READ ); +<<<<<<< HEAD // when we query, request one more item so that we know how to set isTruncated flag +======= + // Wen execting the query, request one more item so that we know how to set isTruncated flag +>>>>>>> 6472e7b... Now really adding the renamed files! SObjectDao sobjectDao = new SObjectDao(); List l = null; @@ -336,25 +439,40 @@ public class S3Engine { response.setNextMarker(l.get(l.size() - 1).getNameKey()); } +<<<<<<< HEAD // SOAP response does not support versioning +======= + // If needed - SOAP response does not support versioning +>>>>>>> 6472e7b... Now really adding the renamed files! response.setContents( composeListBucketContentEntries(l, prefix, delimiter, maxKeys, includeVersions, request.getVersionIdMarker())); response.setCommonPrefixes( composeListBucketPrefixEntries(l, prefix, delimiter, maxKeys)); return response; } /** +<<<<<<< HEAD * To check on bucket policies defined we have to (look for and) evaluate the policy on each * bucket the user owns. * * @param request * @return +======= + * Return a S3ListAllMyBucketResponse which represents a list of all buckets owned by the requester. + * Called from S3BucketAction for GETting all buckets. + * To check on bucket policies defined we have to (look for and) evaluate the policy on each + * bucket the user owns. +>>>>>>> 6472e7b... Now really adding the renamed files! */ public S3ListAllMyBucketsResponse handleRequest(S3ListAllMyBucketsRequest request) { S3ListAllMyBucketsResponse response = new S3ListAllMyBucketsResponse(); SBucketDao bucketDao = new SBucketDao(); +<<<<<<< HEAD // -> "...you can only list buckets for which you are the owner." +======= + // "...you can only list buckets for which you are the owner." +>>>>>>> 6472e7b... Now really adding the renamed files! List buckets = bucketDao.listBuckets(UserContext.current().getCanonicalUserId()); S3CanonicalUser owner = new S3CanonicalUser(); owner.setID(UserContext.current().getCanonicalUserId()); @@ -381,8 +499,18 @@ public class S3Engine { return response; } +<<<<<<< HEAD public S3Response handleRequest(S3SetBucketAccessControlPolicyRequest request) { +======= + /** + * Return an S3Response representing the result of PUTTING the ACL of a given bucket. + * Called from S3BucketAction to PUT its ACL. + */ + + public S3Response handleRequest(S3SetBucketAccessControlPolicyRequest request) + { +>>>>>>> 6472e7b... Now really adding the renamed files! S3Response response = new S3Response(); SBucketDao bucketDao = new SBucketDao(); String bucketName = request.getBucketName(); @@ -392,7 +520,11 @@ public class S3Engine { response.setResultDescription("Bucket does not exist"); return response; } +<<<<<<< HEAD +======= + +>>>>>>> 6472e7b... Now really adding the renamed files! S3PolicyContext context = new S3PolicyContext( PolicyActions.PutBucketAcl, bucketName ); verifyAccess( context, "SBucket", sbucket.getId(), SAcl.PERMISSION_WRITE_ACL ); @@ -404,6 +536,15 @@ public class S3Engine { return response; } +<<<<<<< HEAD +======= + + /** + * Return a S3AccessControlPolicy representing the ACL of a given bucket. + * Called from S3BucketAction to GET its ACL. + */ + +>>>>>>> 6472e7b... Now really adding the renamed files! public S3AccessControlPolicy handleRequest(S3GetBucketAccessControlPolicyRequest request) { S3AccessControlPolicy policy = new S3AccessControlPolicy(); @@ -428,6 +569,7 @@ public class S3Engine { } /** +<<<<<<< HEAD * This function should be called if a multipart upload is aborted OR has completed successfully and * the individual parts have to be cleaned up. * @@ -435,6 +577,14 @@ public class S3Engine { * @param uploadId * @param verifyPermission - if false then don't check the user's permission to clean up the state * @return +======= + * This method should be called if a multipart upload is aborted OR has completed successfully and + * the individual parts have to be cleaned up. + * Called from S3ObjectAction when executing at completion or when aborting multipart upload. + * @param bucketName + * @param uploadId + * @param verifyPermission - If false then do not check the user's permission to clean up the state +>>>>>>> 6472e7b... Now really adding the renamed files! */ public int freeUploadParts(String bucketName, int uploadId, boolean verifyPermission) { @@ -446,12 +596,21 @@ public class S3Engine { return 404; } +<<<<<<< HEAD Tuple tupleBucketHost = getBucketStorageHost(bucket); S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter(tupleBucketHost.getFirst()); try { MultipartLoadDao uploadDao = new MultipartLoadDao(); Tuple exists = uploadDao.multipartExits( uploadId ); +======= + OrderedPair host_storagelocation_pair = getBucketStorageHost(bucket); + S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter(host_storagelocation_pair.getFirst()); + + try { + MultipartLoadDao uploadDao = new MultipartLoadDao(); + OrderedPair exists = uploadDao.multipartExits( uploadId ); +>>>>>>> 6472e7b... Now really adding the renamed files! if (null == exists) { logger.error( "initiateMultipartUpload failed since multipart upload" + uploadId + " does not exist" ); return 404; @@ -474,7 +633,11 @@ public class S3Engine { S3MultipartPart[] parts = uploadDao.getParts( uploadId, 10000, 0 ); for( int i=0; i < parts.length; i++ ) { +<<<<<<< HEAD bucketAdapter.deleteObject( tupleBucketHost.getSecond(), ServiceProvider.getInstance().getMultipartDir(), parts[i].getPath()); +======= + bucketAdapter.deleteObject( host_storagelocation_pair.getSecond(), ServiceProvider.getInstance().getMultipartDir(), parts[i].getPath()); +>>>>>>> 6472e7b... Now really adding the renamed files! } uploadDao.deleteUpload( uploadId ); @@ -495,8 +658,12 @@ public class S3Engine { * The initiator must have permission to write to the bucket in question in order to initiate * a multipart upload. Also check to make sure the special folder used to store parts of * a multipart exists for this bucket. +<<<<<<< HEAD * * @param request +======= + * Called from S3ObjectAction during many stages of multipart upload. +>>>>>>> 6472e7b... Now really adding the renamed files! */ public S3PutObjectInlineResponse initiateMultipartUpload(S3PutObjectInlineRequest request) { @@ -536,7 +703,11 @@ public class S3Engine { /** * Save the object fragment in a special (i.e., hidden) directory inside the same mount point as * the bucket location that the final object will be stored in. +<<<<<<< HEAD * +======= + * Called from S3ObjectAction during many stages of multipart upload. +>>>>>>> 6472e7b... Now really adding the renamed files! * @param request * @param uploadId * @param partNumber @@ -558,14 +729,23 @@ public class S3Engine { context.setKeyName( request.getKey()); verifyAccess( context, "SBucket", bucket.getId(), SAcl.PERMISSION_WRITE ); +<<<<<<< HEAD Tuple tupleBucketHost = getBucketStorageHost(bucket); S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter(tupleBucketHost.getFirst()); +======= + OrderedPair host_storagelocation_pair = getBucketStorageHost(bucket); + S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter(host_storagelocation_pair.getFirst()); +>>>>>>> 6472e7b... Now really adding the renamed files! String itemFileName = new String( uploadId + "-" + partNumber ); InputStream is = null; try { is = request.getDataInputStream(); +<<<<<<< HEAD String md5Checksum = bucketAdapter.saveObject(is, tupleBucketHost.getSecond(), ServiceProvider.getInstance().getMultipartDir(), itemFileName); +======= + String md5Checksum = bucketAdapter.saveObject(is, host_storagelocation_pair.getSecond(), ServiceProvider.getInstance().getMultipartDir(), itemFileName); +>>>>>>> 6472e7b... Now really adding the renamed files! response.setETag(md5Checksum); MultipartLoadDao uploadDao = new MultipartLoadDao(); @@ -596,6 +776,7 @@ public class S3Engine { /** * Create the real object represented by all the parts of the multipart upload. +<<<<<<< HEAD * * @param httpResp - servelet response handle to return the headers of the response (including version header) * @param request - normal parameters need to create a new object (e.g., meta data) @@ -606,6 +787,18 @@ public class S3Engine { * @throws IOException */ public S3PutObjectInlineResponse concatentateMultipartUploads(HttpServletResponse httpResp, S3PutObjectInlineRequest request, S3MultipartPart[] parts, OutputStream os) throws IOException +======= + * Called from S3ObjectAction at completion of multipart upload. + * @param httpResp - Servlet response handle to return the headers of the response (including version header) + * @param request - Normal parameters needed to create a new object (including metadata) + * @param parts - List of files that make up the multipart + * @param outputStream - Response output stream + * N.B. - This method can be long-lasting + * We are required to keep the connection alive by returning whitespace characters back periodically. + */ + + public S3PutObjectInlineResponse concatentateMultipartUploads(HttpServletResponse httpResp, S3PutObjectInlineRequest request, S3MultipartPart[] parts, OutputStream outputStream) throws IOException +>>>>>>> 6472e7b... Now really adding the renamed files! { // [A] Set up and initial error checking S3PutObjectInlineResponse response = new S3PutObjectInlineResponse(); @@ -622,17 +815,29 @@ public class S3Engine { // [B] Now we need to create the final re-assembled object // -> the allocObjectItem checks for the bucket policy PutObject permissions +<<<<<<< HEAD Tuple tupleObjectItem = allocObjectItem(bucket, key, meta, null, request.getCannedAccess()); Tuple tupleBucketHost = getBucketStorageHost(bucket); S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter(tupleBucketHost.getFirst()); String itemFileName = tupleObjectItem.getSecond().getStoredPath(); +======= + OrderedPair object_objectitem_pair = allocObjectItem(bucket, key, meta, null, request.getCannedAccess()); + OrderedPair host_storagelocation_pair = getBucketStorageHost(bucket); + + S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter(host_storagelocation_pair.getFirst()); + String itemFileName = object_objectitem_pair.getSecond().getStoredPath(); +>>>>>>> 6472e7b... Now really adding the renamed files! // -> Amazon defines that we must return a 200 response immediately to the client, but // -> we don't know the version header until we hit here httpResp.setStatus(200); httpResp.setContentType("text/xml; charset=UTF-8"); +<<<<<<< HEAD String version = tupleObjectItem.getSecond().getVersion(); +======= + String version = object_objectitem_pair.getSecond().getVersion(); +>>>>>>> 6472e7b... Now really adding the renamed files! if (null != version) httpResp.addHeader( "x-amz-version-id", version ); httpResp.flushBuffer(); @@ -642,12 +847,28 @@ public class S3Engine { // explicit transaction control to avoid holding transaction during long file concatenation process PersistContext.commitTransaction(); +<<<<<<< HEAD Tuple result = bucketAdapter.concatentateObjects( tupleBucketHost.getSecond(), bucket.getName(), itemFileName, ServiceProvider.getInstance().getMultipartDir(), parts, os ); response.setETag(result.getFirst()); response.setLastModified(DateHelper.toCalendar( tupleObjectItem.getSecond().getLastModifiedTime())); SObjectItemDao itemDao = new SObjectItemDao(); SObjectItem item = itemDao.get( tupleObjectItem.getSecond().getId()); +======= + OrderedPair result = bucketAdapter. + concatentateObjects + ( host_storagelocation_pair.getSecond(), + bucket.getName(), + itemFileName, + ServiceProvider.getInstance().getMultipartDir(), + parts, + outputStream ); + response.setETag(result.getFirst()); + response.setLastModified(DateHelper.toCalendar( object_objectitem_pair.getSecond().getLastModifiedTime())); + + SObjectItemDao itemDao = new SObjectItemDao(); + SObjectItem item = itemDao.get( object_objectitem_pair.getSecond().getId()); +>>>>>>> 6472e7b... Now really adding the renamed files! item.setMd5(result.getFirst()); item.setStoredSize(result.getSecond().longValue()); response.setResultCode(200); @@ -660,6 +881,14 @@ public class S3Engine { return response; } +<<<<<<< HEAD +======= + /** + * Return a S3PutObjectInlineResponse which represents an object being created into a bucket + * Called from S3ObjectAction when PUTting or POTing an object. + */ + +>>>>>>> 6472e7b... Now really adding the renamed files! public S3PutObjectInlineResponse handleRequest(S3PutObjectInlineRequest request) { S3PutObjectInlineResponse response = new S3PutObjectInlineResponse(); @@ -674,6 +903,7 @@ public class S3Engine { if (bucket == null) throw new NoSuchObjectException("Bucket " + bucketName + " does not exist"); +<<<<<<< HEAD // -> is the caller allowed to write the object? // -> the allocObjectItem checks for the bucket policy PutObject permissions Tuple tupleObjectItem = allocObjectItem(bucket, key, meta, acl, request.getCannedAccess()); @@ -681,6 +911,15 @@ public class S3Engine { S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter(tupleBucketHost.getFirst()); String itemFileName = tupleObjectItem.getSecond().getStoredPath(); +======= + // Is the caller allowed to write the object? + // The allocObjectItem checks for the bucket policy PutObject permissions + OrderedPair object_objectitem_pair = allocObjectItem(bucket, key, meta, acl, request.getCannedAccess()); + OrderedPair host_storagelocation_pair = getBucketStorageHost(bucket); + + S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter(host_storagelocation_pair.getFirst()); + String itemFileName = object_objectitem_pair.getSecond().getStoredPath(); +>>>>>>> 6472e7b... Now really adding the renamed files! InputStream is = null; try { @@ -688,6 +927,7 @@ public class S3Engine { PersistContext.commitTransaction(); is = request.getDataInputStream(); +<<<<<<< HEAD String md5Checksum = bucketAdapter.saveObject(is, tupleBucketHost.getSecond(), bucket.getName(), itemFileName); response.setETag(md5Checksum); response.setLastModified(DateHelper.toCalendar( tupleObjectItem.getSecond().getLastModifiedTime())); @@ -695,6 +935,15 @@ public class S3Engine { SObjectItemDao itemDao = new SObjectItemDao(); SObjectItem item = itemDao.get( tupleObjectItem.getSecond().getId()); +======= + String md5Checksum = bucketAdapter.saveObject(is, host_storagelocation_pair.getSecond(), bucket.getName(), itemFileName); + response.setETag(md5Checksum); + response.setLastModified(DateHelper.toCalendar( object_objectitem_pair.getSecond().getLastModifiedTime())); + response.setVersion( object_objectitem_pair.getSecond().getVersion()); + + SObjectItemDao itemDao = new SObjectItemDao(); + SObjectItem item = itemDao.get( object_objectitem_pair.getSecond().getId()); +>>>>>>> 6472e7b... Now really adding the renamed files! item.setMd5(md5Checksum); item.setStoredSize(contentLength); PersistContext.getSession().save(item); @@ -715,6 +964,14 @@ public class S3Engine { return response; } +<<<<<<< HEAD +======= + + /** + * Return a S3PutObjectResponse which represents an object being created into a bucket + * Called from S3RestServlet when processing a DIME request. + */ +>>>>>>> 6472e7b... Now really adding the renamed files! public S3PutObjectResponse handleRequest(S3PutObjectRequest request) { @@ -729,6 +986,7 @@ public class S3Engine { SBucket bucket = bucketDao.getByName(bucketName); if(bucket == null) throw new NoSuchObjectException("Bucket " + bucketName + " does not exist"); +<<<<<<< HEAD // -> is the caller allowed to write the object? // -> the allocObjectItem checks for the bucket policy PutObject permissions Tuple tupleObjectItem = allocObjectItem(bucket, key, meta, acl, null); @@ -736,18 +994,36 @@ public class S3Engine { S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter(tupleBucketHost.getFirst()); String itemFileName = tupleObjectItem.getSecond().getStoredPath(); +======= + // Is the caller allowed to write the object? + // The allocObjectItem checks for the bucket policy PutObject permissions + OrderedPair object_objectitem_pair = allocObjectItem(bucket, key, meta, acl, null); + OrderedPair host_storagelocation_pair = getBucketStorageHost(bucket); + + S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter(host_storagelocation_pair.getFirst()); + String itemFileName = object_objectitem_pair.getSecond().getStoredPath(); +>>>>>>> 6472e7b... Now really adding the renamed files! InputStream is = null; try { // explicit transaction control to avoid holding transaction during file-copy process PersistContext.commitTransaction(); is = request.getInputStream(); +<<<<<<< HEAD String md5Checksum = bucketAdapter.saveObject(is, tupleBucketHost.getSecond(), bucket.getName(), itemFileName); response.setETag(md5Checksum); response.setLastModified(DateHelper.toCalendar( tupleObjectItem.getSecond().getLastModifiedTime())); SObjectItemDao itemDao = new SObjectItemDao(); SObjectItem item = itemDao.get( tupleObjectItem.getSecond().getId()); +======= + String md5Checksum = bucketAdapter.saveObject(is, host_storagelocation_pair.getSecond(), bucket.getName(), itemFileName); + response.setETag(md5Checksum); + response.setLastModified(DateHelper.toCalendar( object_objectitem_pair.getSecond().getLastModifiedTime())); + + SObjectItemDao itemDao = new SObjectItemDao(); + SObjectItem item = itemDao.get( object_objectitem_pair.getSecond().getId()); +>>>>>>> 6472e7b... Now really adding the renamed files! item.setMd5(md5Checksum); item.setStoredSize(contentLength); PersistContext.getSession().save(item); @@ -769,11 +1045,18 @@ public class S3Engine { /** * The ACL of an object is set at the object version level. By default, PUT sets the ACL of the latest +<<<<<<< HEAD * version of an object. To set the ACL of a different version, use the versionId subresource. * * @param request * @return */ +======= + * version of an object. To set the ACL of a different version, using the versionId subresource. + * Called from S3ObjectAction to PUT an object's ACL. + */ + +>>>>>>> 6472e7b... Now really adding the renamed files! public S3Response handleRequest(S3SetObjectAccessControlPolicyRequest request) { S3PolicyContext context = null; @@ -841,10 +1124,16 @@ public class S3Engine { /** * By default, GET returns ACL information about the latest version of an object. To return ACL * information about a different version, use the versionId subresource +<<<<<<< HEAD * * @param request * @return */ +======= + * Called from S3ObjectAction to get an object's ACL. + */ + +>>>>>>> 6472e7b... Now really adding the renamed files! public S3AccessControlPolicy handleRequest(S3GetObjectAccessControlPolicyRequest request) { S3PolicyContext context = null; @@ -909,11 +1198,18 @@ public class S3Engine { } /** +<<<<<<< HEAD * Implements both GetObject and GetObjectExtended. * * @param request * @return */ +======= + * Handle requests for GET object and HEAD "get object extended" + * Called from S3ObjectAction for GET and HEAD of an object. + */ + +>>>>>>> 6472e7b... Now really adding the renamed files! public S3GetObjectResponse handleRequest(S3GetObjectRequest request) { S3GetObjectResponse response = new S3GetObjectResponse(); @@ -1000,7 +1296,11 @@ public class S3Engine { { int i = 0; S3MetaDataEntry[] metaEntries = new S3MetaDataEntry[ itemMetaData.size() ]; +<<<<<<< HEAD ListIterator it = itemMetaData.listIterator(); +======= + ListIterator it = itemMetaData.listIterator(); +>>>>>>> 6472e7b... Now really adding the renamed files! while( it.hasNext()) { SMeta oneTag = (SMeta)it.next(); S3MetaDataEntry oneEntry = new S3MetaDataEntry(); @@ -1025,7 +1325,11 @@ public class S3Engine { response.setVersion( item.getVersion()); if (request.isInlineData()) { +<<<<<<< HEAD Tuple tupleSHostInfo = getBucketStorageHost(sbucket); +======= + OrderedPair tupleSHostInfo = getBucketStorageHost(sbucket); +>>>>>>> 6472e7b... Now really adding the renamed files! S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter(tupleSHostInfo.getFirst()); if ( 0 <= bytesStart && 0 <= bytesEnd ) @@ -1041,18 +1345,31 @@ public class S3Engine { } /** +<<<<<<< HEAD * In one place we handle both versioning and non-versioning delete requests. */ public S3Response handleRequest(S3DeleteObjectRequest request) { // -> verify that the bucket and object exist +======= + * Handle object deletion requests, both versioning and non-versioning requirements. + * Called from S3ObjectAction for deletion. + */ + public S3Response handleRequest(S3DeleteObjectRequest request) + { + // Verify that the bucket and object exist +>>>>>>> 6472e7b... Now really adding the renamed files! S3Response response = new S3Response(); SBucketDao bucketDao = new SBucketDao(); String bucketName = request.getBucketName(); SBucket sbucket = bucketDao.getByName( bucketName ); if (sbucket == null) { response.setResultCode(404); +<<<<<<< HEAD response.setResultDescription("Bucket does not exist"); +======= + response.setResultDescription("Bucket " + bucketName + " does not exist"); +>>>>>>> 6472e7b... Now really adding the renamed files! return response; } @@ -1061,12 +1378,20 @@ public class S3Engine { SObject sobject = objectDao.getByNameKey( sbucket, nameKey ); if (sobject == null) { response.setResultCode(404); +<<<<<<< HEAD response.setResultDescription("Bucket does not exist"); +======= + response.setResultDescription("No object with key " + nameKey + " exists in bucket " + bucketName); +>>>>>>> 6472e7b... Now really adding the renamed files! return response; } +<<<<<<< HEAD // -> versioning controls what delete means +======= + // Discover whether versioning is enabled. If so versioning requires the setting of a deletion marker. +>>>>>>> 6472e7b... Now really adding the renamed files! String storedPath = null; SObjectItem item = null; int versioningStatus = sbucket.getVersioningStatus(); @@ -1079,12 +1404,20 @@ public class S3Engine { verifyAccess( context, "SBucket", sbucket.getId(), SAcl.PERMISSION_WRITE ); if (null == wantVersion) { +<<<<<<< HEAD // -> if versioning is on and no versionId is given then we just write a deletion marker +======= + // If versioning is on and no versionId is given then we just write a deletion marker +>>>>>>> 6472e7b... Now really adding the renamed files! sobject.setDeletionMark( UUID.randomUUID().toString()); objectDao.update( sobject ); } else { +<<<<<<< HEAD // -> are we removing the delete marker? +======= + // Otherwise remove the deletion marker if this has been set +>>>>>>> 6472e7b... Now really adding the renamed files! String deletionMarker = sobject.getDeletionMark(); if (null != deletionMarker && wantVersion.equalsIgnoreCase( deletionMarker )) { sobject.setDeletionMark( null ); @@ -1093,13 +1426,21 @@ public class S3Engine { return response; } +<<<<<<< HEAD // -> if versioning is on and the versionId is given then we delete the object matching that version +======= + // If versioning is on and the versionId is given (non-null) then delete the object matching that version +>>>>>>> 6472e7b... Now really adding the renamed files! if ( null == (item = sobject.getVersion( wantVersion ))) { response.setResultCode(404); return response; } else { +<<<<<<< HEAD // -> just delete the one item that matches the versionId from the database +======= + // Providing versionId is non-null, then just delete the one item that matches the versionId from the database +>>>>>>> 6472e7b... Now really adding the renamed files! storedPath = item.getStoredPath(); sobject.deleteItem( item.getId()); objectDao.update( sobject ); @@ -1107,7 +1448,11 @@ public class S3Engine { } } else +<<<<<<< HEAD { // -> if versioning is off then we do delete the null object +======= + { // If versioning is off then we do delete the null object +>>>>>>> 6472e7b... Now really adding the renamed files! S3PolicyContext context = new S3PolicyContext( PolicyActions.DeleteObject, bucketName ); context.setKeyName( nameKey ); verifyAccess( context, "SBucket", sbucket.getId(), SAcl.PERMISSION_WRITE ); @@ -1117,10 +1462,17 @@ public class S3Engine { return response; } else { +<<<<<<< HEAD // -> if no item with a null version then we are done if (null == item.getVersion()) { // -> remove the entire object // -> cascade-deleting can delete related SObject/SObjectItem objects, but not SAcl and SMeta objects. +======= + // If there is no item with a null version then we are done + if (null == item.getVersion()) { + // Otherwiswe remove the entire object + // Cascade-deleting can delete related SObject/SObjectItem objects, but not SAcl and SMeta objects. +>>>>>>> 6472e7b... Now really adding the renamed files! storedPath = item.getStoredPath(); deleteMetaData( item.getId()); deleteObjectAcls( "SObjectItem", item.getId()); @@ -1129,12 +1481,21 @@ public class S3Engine { } } +<<<<<<< HEAD // -> delete the file holding the object if (null != storedPath) { Tuple tupleBucketHost = getBucketStorageHost( sbucket ); S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter( tupleBucketHost.getFirst()); bucketAdapter.deleteObject( tupleBucketHost.getSecond(), bucketName, storedPath ); +======= + // Delete the file holding the object + if (null != storedPath) + { + OrderedPair host_storagelocation_pair = getBucketStorageHost( sbucket ); + S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter( host_storagelocation_pair.getFirst()); + bucketAdapter.deleteObject( host_storagelocation_pair.getSecond(), bucketName, storedPath ); +>>>>>>> 6472e7b... Now really adding the renamed files! } response.setResultCode(204); @@ -1147,7 +1508,11 @@ public class S3Engine { List itemMetaData = metaDao.getByTarget( "SObjectItem", itemId ); if (null != itemMetaData) { +<<<<<<< HEAD ListIterator it = itemMetaData.listIterator(); +======= + ListIterator it = itemMetaData.listIterator(); +>>>>>>> 6472e7b... Now really adding the renamed files! while( it.hasNext()) { SMeta oneTag = (SMeta)it.next(); metaDao.delete( oneTag ); @@ -1160,7 +1525,11 @@ public class S3Engine { List itemAclData = aclDao.listGrants( target, itemId ); if (null != itemAclData) { +<<<<<<< HEAD ListIterator it = itemAclData.listIterator(); +======= + ListIterator it = itemAclData.listIterator(); +>>>>>>> 6472e7b... Now really adding the renamed files! while( it.hasNext()) { SAcl oneTag = (SAcl)it.next(); aclDao.delete( oneTag ); @@ -1173,7 +1542,11 @@ public class S3Engine { List bucketAclData = aclDao.listGrants( "SBucket", bucketId ); if (null != bucketAclData) { +<<<<<<< HEAD ListIterator it = bucketAclData.listIterator(); +======= + ListIterator it = bucketAclData.listIterator(); +>>>>>>> 6472e7b... Now really adding the renamed files! while( it.hasNext()) { SAcl oneTag = (SAcl)it.next(); aclDao.delete( oneTag ); @@ -1234,11 +1607,19 @@ public class S3Engine { { hitIdMarker = (null == versionIdMarker ? true : false); +<<<<<<< HEAD // -> this supports the REST call GET /?versions String deletionMarker = sobject.getDeletionMark(); if ( null != deletionMarker ) { // -> TODO we don't save the timestamp when something is deleted +======= + // This supports GET REST calls with /?versions + String deletionMarker = sobject.getDeletionMark(); + if ( null != deletionMarker ) + { + // TODO we should also save the timestamp when something is deleted +>>>>>>> 6472e7b... Now really adding the renamed files! S3ListBucketObjectEntry entry = new S3ListBucketObjectEntry(); entry.setKey(sobject.getNameKey()); entry.setVersion( deletionMarker ); @@ -1318,18 +1699,30 @@ public class S3Engine { return entry; } +<<<<<<< HEAD public Tuple getBucketStorageHost(SBucket bucket) +======= + private OrderedPair getBucketStorageHost(SBucket bucket) +>>>>>>> 6472e7b... Now really adding the renamed files! { MHostMountDao mountDao = new MHostMountDao(); SHost shost = bucket.getShost(); if(shost.getHostType() == SHost.STORAGE_HOST_TYPE_LOCAL) { +<<<<<<< HEAD return new Tuple(shost, shost.getExportRoot()); +======= + return new OrderedPair(shost, shost.getExportRoot()); +>>>>>>> 6472e7b... Now really adding the renamed files! } MHostMount mount = mountDao.getHostMount(ServiceProvider.getInstance().getManagementHostId(), shost.getId()); if(mount != null) { +<<<<<<< HEAD return new Tuple(shost, mount.getMountPath()); +======= + return new OrderedPair(shost, mount.getMountPath()); +>>>>>>> 6472e7b... Now really adding the renamed files! } // need to redirect request to other node @@ -1364,7 +1757,11 @@ public class S3Engine { * @param overrideName * @return */ +<<<<<<< HEAD private Tuple allocBucketStorageHost(String bucketName, String overrideName) +======= + private OrderedPair allocBucketStorageHost(String bucketName, String overrideName) +>>>>>>> 6472e7b... Now really adding the renamed files! { MHostDao mhostDao = new MHostDao(); SHostDao shostDao = new SHostDao(); @@ -1379,10 +1776,17 @@ public class S3Engine { MHostMount mount = mounts[random.nextInt(mounts.length)]; S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter(mount.getShost()); bucketAdapter.createContainer(mount.getMountPath(), (null != overrideName ? overrideName : bucketName)); +<<<<<<< HEAD return new Tuple(mount.getShost(), mount.getMountPath()); } // To make things simple, only allow one local mounted storage root +======= + return new OrderedPair(mount.getShost(), mount.getMountPath()); + } + + // To make things simple, only allow one local mounted storage root TODO - Change in the future +>>>>>>> 6472e7b... Now really adding the renamed files! String localStorageRoot = ServiceProvider.getInstance().getStartupProperties().getProperty("storage.root"); if(localStorageRoot != null) { SHost localSHost = shostDao.getLocalStorageHost(mhost.getId(), localStorageRoot); @@ -1391,7 +1795,11 @@ public class S3Engine { S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter(localSHost); bucketAdapter.createContainer(localSHost.getExportRoot(),(null != overrideName ? overrideName : bucketName)); +<<<<<<< HEAD return new Tuple(localSHost, localStorageRoot); +======= + return new OrderedPair(localSHost, localStorageRoot); +>>>>>>> 6472e7b... Now really adding the renamed files! } throw new OutOfStorageException("No storage host is available"); @@ -1415,7 +1823,11 @@ public class S3Engine { * @throws IOException */ @SuppressWarnings("deprecation") +<<<<<<< HEAD public Tuple allocObjectItem(SBucket bucket, String nameKey, S3MetaDataEntry[] meta, S3AccessControlList acl, String cannedAccessPolicy) +======= + public OrderedPair allocObjectItem(SBucket bucket, String nameKey, S3MetaDataEntry[] meta, S3AccessControlList acl, String cannedAccessPolicy) +>>>>>>> 6472e7b... Now really adding the renamed files! { SObjectDao objectDao = new SObjectDao(); SObjectItemDao objectItemDao = new SObjectItemDao(); @@ -1431,9 +1843,16 @@ public class S3Engine { S3PolicyContext context = new S3PolicyContext( PolicyActions.PutObject, bucket.getName()); context.setKeyName( nameKey ); context.setEvalParam( ConditionKeys.Acl, cannedAccessPolicy); +<<<<<<< HEAD verifyAccess( context, "SBucket", bucket.getId(), SAcl.PERMISSION_WRITE ); // [A] If versioning is off them we over write a null object item +======= + + verifyAccess( context, "SBucket", bucket.getId(), SAcl.PERMISSION_WRITE ); // TODO - check this validates plain POSTs + + // [B] If versioning is off them we over write a null object item +>>>>>>> 6472e7b... Now really adding the renamed files! SObject object = objectDao.getByNameKey(bucket, nameKey); if ( object != null ) { @@ -1521,7 +1940,11 @@ public class S3Engine { } session.update(item); +<<<<<<< HEAD return new Tuple(object, item); +======= + return new OrderedPair(object, item); +>>>>>>> 6472e7b... Now really adding the renamed files! } @@ -1529,6 +1952,7 @@ public class S3Engine { * Access controls that are specified via the "x-amz-acl:" headers in REST requests. * Note that canned policies can be set when the object's contents are set */ +<<<<<<< HEAD private void setCannedAccessControls( String cannedAccessPolicy, String target, long objectId, SBucket bucket ) { if ( cannedAccessPolicy.equalsIgnoreCase( "public-read" )) @@ -1568,6 +1992,23 @@ public class S3Engine { else setDefaultAcls( target, objectId, SAcl.PERMISSION_FULL, SAcl.PERMISSION_FULL, bucket.getOwnerCanonicalId()); } else throw new UnsupportedException( "Unknown Canned Access Policy: " + cannedAccessPolicy + " is not supported" ); +======= + public void setCannedAccessControls( String cannedAccessPolicy, String target, long objectId, SBucket bucket ) + { + // Find the permission and symbol for the principal corresponding to the requested cannedAccessPolicy + Triple permission_permission_symbol_triple = + SAcl.getCannedAccessControls(cannedAccessPolicy, target, bucket.getOwnerCanonicalId()); + if ( null == permission_permission_symbol_triple.getThird() ) + setSingleAcl(target, objectId, permission_permission_symbol_triple.getFirst()); + else + { setDefaultAcls( target, + objectId, + permission_permission_symbol_triple.getFirst(), // permission according to ownership of object + permission_permission_symbol_triple.getSecond(), // permission according to ownership of bucket + permission_permission_symbol_triple.getThird() ); // "symbol" to indicate principal or otherwise name of owner + + } +>>>>>>> 6472e7b... Now really adding the renamed files! } @@ -1588,10 +2029,17 @@ public class S3Engine { aclDao.save( target, targetId, defaultAcl ); } } +<<<<<<< HEAD /** * Note that we use the Cloud Stack API Access key for the Canonical User Id everywhere * (i.e., for buckets, and objects). +======= + + + /** + * The Cloud Stack API Access key is used for for the Canonical User Id everywhere (buckets and objects). +>>>>>>> 6472e7b... Now really adding the renamed files! * * @param owner - this can be the Cloud Access Key for a bucket owner or one of the * following special symbols: @@ -1623,7 +2071,15 @@ public class S3Engine { { S3BucketPolicy policy = null; +<<<<<<< HEAD // -> on error of getting a policy ignore it +======= + // Ordinarily a REST request will pass in an S3PolicyContext for a given bucket by this stage. The HttpServletRequest object + // should be held in the UserContext ready for extraction of the S3BucketPolicy. + // If there is an error in obtaining the request object or in loading the policy then log the failure and return a S3PolicyContext + // which indicates DEFAULT_DENY. Where there is no failure, the policy returned should be specific to the Canonical User ID of the requester. + +>>>>>>> 6472e7b... Now really adding the renamed files! try { // -> in SOAP the HttpServletRequest object is hidden and not passed around if (null != context) { @@ -1669,6 +2125,7 @@ public class S3Engine { } /** +<<<<<<< HEAD * This function verifies that the accessing client has the requested * permission on the object/bucket/Acl represented by the tuble: * @@ -1677,6 +2134,16 @@ public class S3Engine { * * For cases where an ACL is meant for any anonymous user (or 'AllUsers') we place a "A" for the * Canonical User Id ("A" is not a legal Cloud Stack Access key). +======= + * This method verifies that the accessing client has the requested + * permission on the object/bucket/Acl represented by the tuple: + * + * For cases where an ACL is meant for any authenticated user we place a "*" for the + * Canonical User Id. N.B. - "*" is not a legal Cloud (Bridge) Access key. + * + * For cases where an ACL is meant for any anonymous user (or 'AllUsers') we place a "A" for the + * Canonical User Id. N.B. - "A" is not a legal Cloud (Bridge) Access key. +>>>>>>> 6472e7b... Now really adding the renamed files! */ public static void accessAllowed( String target, long targetId, int requestedPermission ) { @@ -1684,6 +2151,7 @@ public class S3Engine { SAclDao aclDao = new SAclDao(); +<<<<<<< HEAD // -> if an annoymous request, then canonicalUserId is an empty string String userId = UserContext.current().getCanonicalUserId(); if ( 0 == userId.length()) @@ -1698,11 +2166,31 @@ public class S3Engine { // -> or maybe there is any principal authenticated ACL set for this ? if (hasPermission( aclDao.listGrants( target, targetId, "*" ), requestedPermission )) return; } +======= + // If an annoymous request, then canonicalUserId is an empty string + String userId = UserContext.current().getCanonicalUserId(); + if ( 0 == userId.length()) + { + // Is an anonymous principal ACL set for this ? + if (hasPermission( aclDao.listGrants( target, targetId, "A" ), requestedPermission )) return; + } + else + { + if (hasPermission( aclDao.listGrants( target, targetId, userId ), requestedPermission )) return; + // Or alternatively is there is any principal authenticated ACL set for this ? + if (hasPermission( aclDao.listGrants( target, targetId, "*" ), requestedPermission )) return; + } + // No privileges implies that no access is allowed in the case of an anonymous user +>>>>>>> 6472e7b... Now really adding the renamed files! throw new PermissionDeniedException( "Access Denied - ACLs do not give user the required permission" ); } /** +<<<<<<< HEAD * This function assumes that the bucket has been tested to make sure it exists before +======= + * This method assumes that the bucket has been tested to make sure it exists before +>>>>>>> 6472e7b... Now really adding the renamed files! * it is called. * * @param context @@ -1712,7 +2200,11 @@ public class S3Engine { public static S3BucketPolicy loadPolicy( S3PolicyContext context ) throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException, ParseException { +<<<<<<< HEAD Tuple result = ServiceProvider.getInstance().getBucketPolicy( context.getBucketName()); +======= + OrderedPair result = ServiceProvider.getInstance().getBucketPolicy( context.getBucketName()); +>>>>>>> 6472e7b... Now really adding the renamed files! S3BucketPolicy policy = result.getFirst(); if ( null == policy ) { @@ -1772,7 +2264,12 @@ public class S3Engine { int fourth = Integer.parseInt( parts[3] ); throw new InvalidBucketName( bucketName + " is formatted as an IP address" ); } +<<<<<<< HEAD catch( NumberFormatException e ) {} +======= + catch( NumberFormatException e ) + {throw new InvalidBucketName( bucketName);} +>>>>>>> 6472e7b... Now really adding the renamed files! } @@ -1804,12 +2301,21 @@ public class S3Engine { } } +<<<<<<< HEAD private static boolean hasPermission( List priviledges, int requestedPermission ) { ListIterator it = priviledges.listIterator(); while( it.hasNext()) { // -> is the requested permission "contained" in one or the granted rights for this user +======= + private static boolean hasPermission( List privileges, int requestedPermission ) + { + ListIterator it = privileges.listIterator(); + while( it.hasNext()) + { + // True providing the requested permission is contained in one or the granted rights for this user. False otherwise. +>>>>>>> 6472e7b... Now really adding the renamed files! SAcl rights = (SAcl)it.next(); int permission = rights.getPermission(); if (requestedPermission == (permission & requestedPermission)) return true; @@ -1818,13 +2324,21 @@ public class S3Engine { } /** +<<<<<<< HEAD * ifRange is true and IfUnmodifiedSince or IfMatch fails then we return the entire object (indicated by +======= + * ifRange is true and ifUnmodifiedSince or IfMatch fails then we return the entire object (indicated by +>>>>>>> 6472e7b... Now really adding the renamed files! * returning a -1 as the function result. * * @param ifCond - conditional get defined by these tests * @param lastModified - value used on ifModifiedSince or ifUnmodifiedSince * @param ETag - value used on ifMatch and ifNoneMatch +<<<<<<< HEAD * @param ifRange - using an If-Range HTTP functionality +======= + * @param ifRange - using an if-Range HTTP functionality +>>>>>>> 6472e7b... Now really adding the renamed files! * @return -1 means return the entire object with an HTTP 200 (not a subrange) */ private int conditionPassed( S3ConditionalHeaders ifCond, Date lastModified, String ETag, boolean ifRange ) diff --git a/awsapi/src/com/cloud/bridge/service/core/s3/S3Grant.java b/awsapi/src/com/cloud/bridge/service/core/s3/S3Grant.java index acc7e26672e..ee14c659cff 100644 --- a/awsapi/src/com/cloud/bridge/service/core/s3/S3Grant.java +++ b/awsapi/src/com/cloud/bridge/service/core/s3/S3Grant.java @@ -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 grants) { if(grants != null) { @@ -70,4 +89,8 @@ public class S3Grant { } return null; } +<<<<<<< HEAD +======= + +>>>>>>> 6472e7b... Now really adding the renamed files! } diff --git a/awsapi/src/com/cloud/bridge/service/core/s3/S3HostCallingFormat.java b/awsapi/src/com/cloud/bridge/service/core/s3/S3HostCallingFormat.java new file mode 100755 index 00000000000..d5ea1542036 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/service/core/s3/S3HostCallingFormat.java @@ -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; + } + } +} \ No newline at end of file diff --git a/awsapi/src/com/cloud/bridge/service/core/s3/S3ListAllMyBucketsEntry.java b/awsapi/src/com/cloud/bridge/service/core/s3/S3ListAllMyBucketsEntry.java index 6ecc71b7670..e11a7c146a4 100644 --- a/awsapi/src/com/cloud/bridge/service/core/s3/S3ListAllMyBucketsEntry.java +++ b/awsapi/src/com/cloud/bridge/service/core/s3/S3ListAllMyBucketsEntry.java @@ -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) { diff --git a/awsapi/src/com/cloud/bridge/service/core/s3/S3PutObjectInlineRequest.java b/awsapi/src/com/cloud/bridge/service/core/s3/S3PutObjectInlineRequest.java index 4a3ab7999ca..12eedf9b881 100644 --- a/awsapi/src/com/cloud/bridge/service/core/s3/S3PutObjectInlineRequest.java +++ b/awsapi/src/com/cloud/bridge/service/core/s3/S3PutObjectInlineRequest.java @@ -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; diff --git a/awsapi/src/com/cloud/bridge/service/core/s3/S3PutObjectInlineResponse.java b/awsapi/src/com/cloud/bridge/service/core/s3/S3PutObjectInlineResponse.java index 16f5d13d9c7..9a88eccdd1d 100644 --- a/awsapi/src/com/cloud/bridge/service/core/s3/S3PutObjectInlineResponse.java +++ b/awsapi/src/com/cloud/bridge/service/core/s3/S3PutObjectInlineResponse.java @@ -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; } diff --git a/awsapi/src/com/cloud/bridge/util/CloudSessionFactory.java b/awsapi/src/com/cloud/bridge/util/CloudSessionFactory.java index 51bfa299ca1..8657836bef1 100644 --- a/awsapi/src/com/cloud/bridge/util/CloudSessionFactory.java +++ b/awsapi/src/com/cloud/bridge/util/CloudSessionFactory.java @@ -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() { diff --git a/awsapi/src/com/cloud/bridge/util/DatabindingConverterUtil.java b/awsapi/src/com/cloud/bridge/util/DatabindingConverterUtil.java new file mode 100644 index 00000000000..3deb4b3c475 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/util/DatabindingConverterUtil.java @@ -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 + + +} diff --git a/awsapi/src/com/cloud/bridge/util/HeaderParam.java b/awsapi/src/com/cloud/bridge/util/HeaderParam.java index 53d7d7da48a..d6d380f6881 100644 --- a/awsapi/src/com/cloud/bridge/util/HeaderParam.java +++ b/awsapi/src/com/cloud/bridge/util/HeaderParam.java @@ -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; } diff --git a/awsapi/src/com/cloud/bridge/util/ISO8601SimpleDateTimeFormat.java b/awsapi/src/com/cloud/bridge/util/ISO8601SimpleDateTimeFormat.java new file mode 100755 index 00000000000..5b9f7bc5d45 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/util/ISO8601SimpleDateTimeFormat.java @@ -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; + } + + + + } + diff --git a/awsapi/src/com/cloud/bridge/util/OrderedPair.java b/awsapi/src/com/cloud/bridge/util/OrderedPair.java new file mode 100644 index 00000000000..beaae9baebb --- /dev/null +++ b/awsapi/src/com/cloud/bridge/util/OrderedPair.java @@ -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 + * @param + */ +public class OrderedPair { + T1 first; + T2 second; + + public OrderedPair(T1 t1, T2 t2) { + first = t1; + second = t2; + } + + public T1 getFirst() { + return first; + } + + public OrderedPair setFirst(T1 t1) { + first = t1; + return this; + } + + public T2 getSecond() { + return second; + } + + public OrderedPair setSecond(T2 t2) { + second = t2; + return this; + } +} diff --git a/awsapi/src/com/cloud/bridge/util/RestAuth.java b/awsapi/src/com/cloud/bridge/util/RestAuth.java index 9fa88de80d4..90d8e414bda 100644 --- a/awsapi/src/com/cloud/bridge/util/RestAuth.java +++ b/awsapi/src/com/cloud/bridge/util/RestAuth.java @@ -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 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 allowedQueryParams; + + public RestAuth() { + // these must be lexicographically sorted + AmazonHeaders = new TreeMap(); + allowedQueryParams = new HashSet() {{ + 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 ] + + * + [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 subResources = new TreeSet(); + + 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 ] + + * + + * [ 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 headers = AmazonHeaders.values(); + Iterator 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! diff --git a/awsapi/src/com/cloud/bridge/util/StringHelper.java b/awsapi/src/com/cloud/bridge/util/StringHelper.java index 9cff1a1fc53..1c185a899af 100644 --- a/awsapi/src/com/cloud/bridge/util/StringHelper.java +++ b/awsapi/src/com/cloud/bridge/util/StringHelper.java @@ -19,11 +19,18 @@ import java.io.IOException; import java.io.InputStream; /** +<<<<<<< HEAD * @author Kelven +======= + * @author Kelven, John Zucker + * Provide converters for regexp (case independent tokens) + * Also provide upper case or lower case (default) converters for byte array b[] to hex String +>>>>>>> 6472e7b... Now really adding the renamed files! */ public class StringHelper { public static final String EMPTY_STRING = ""; +<<<<<<< HEAD private static final char[] hexChars = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; public static String toHexString(byte[] b) { @@ -31,6 +38,30 @@ public class StringHelper { for (int i = 0; i < b.length; i++) { sb.append(hexChars[ (int)(((int)b[i] >> 4) & 0x0f)]); sb.append(hexChars[ (int)(((int)b[i]) & 0x0f)]); +======= + private static final char[] hexCharsUpperCase = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; + + private static final char[] hexCharsLowerCase = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' }; + + /* Convert byte array b[] into an uppercase hex string + */ + public static String toHexStringUpperCase(byte[] b) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < b.length; i++) { + sb.append(hexCharsUpperCase[ (int)(((int)b[i] >> 4) & 0x0f)]); + sb.append(hexCharsUpperCase[ (int)(((int)b[i]) & 0x0f)]); + } + return sb.toString(); + } + + /* Convert byte array b[] into a lowercase (default) hex string + */ + public static String toHexString(byte[] b) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < b.length; i++) { + sb.append(hexCharsLowerCase[ (int)(((int)b[i] >> 4) & 0x0f)]); + sb.append(hexCharsLowerCase[ (int)(((int)b[i]) & 0x0f)]); +>>>>>>> 6472e7b... Now really adding the renamed files! } return sb.toString(); } diff --git a/awsapi/src/com/cloud/bridge/util/Triple.java b/awsapi/src/com/cloud/bridge/util/Triple.java new file mode 100644 index 00000000000..146e2917d75 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/util/Triple.java @@ -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; + +/** + * @author Kelven Yang, John Zucker + * Reusable class whose instances encode any triple (or 3-tuple) of values of types T1, T2 and T3 + * Provide getters: getFirst(), getSecond(), getThird() + * Provide setters: setFirst(val), setSecond(val), setThird(val) + * @param + * @param + * @param + */ +public class Triple { + T1 first; + T2 second; + T3 third; + + public Triple(T1 t1, T2 t2, T3 t3) { + first = t1; + second = t2; + third = t3; + } + + public T1 getFirst() { + return first; + } + + public Triple setFirst(T1 t1) { + first = t1; + return this; + } + + public T2 getSecond() { + return second; + } + + public Triple setSecond(T2 t2) { + second = t2; + return this; + } + + public T3 getThird() { + return third; + } + + public Triple setThird(T3 t3) { + third = t3; + return this; + } +} \ No newline at end of file diff --git a/awsapi/src/com/cloud/stack/CloudStackApi.java b/awsapi/src/com/cloud/stack/CloudStackApi.java index 73d261cae38..d0bf1f20314 100644 --- a/awsapi/src/com/cloud/stack/CloudStackApi.java +++ b/awsapi/src/com/cloud/stack/CloudStackApi.java @@ -1194,7 +1194,11 @@ public class CloudStackApi { CloudStackCommand cmd = new CloudStackCommand(ApiConstants.DELETE_SNAPSHOT); if (cmd != null) cmd.setParam(ApiConstants.ID, id); +<<<<<<< HEAD return _client.call(cmd, apiKey, secretKey, true, ApiConstants.DELETE_SNAPSHOT_RESPONSE, null, CloudStackInfoResponse.class); +======= + return _client.call(cmd, apiKey, secretKey, true, ApiConstants.DELETE_SNAPSHOT_RESPONSE, ApiConstants.SNAPSHOT, CloudStackInfoResponse.class); +>>>>>>> 6472e7b... Now really adding the renamed files! } /** @@ -1235,7 +1239,11 @@ public class CloudStackApi { if (id != null) cmd.setParam(ApiConstants.ID, id); if (ids != null) cmd.setParam(ApiConstants.IDS, ids); } +<<<<<<< HEAD return _client.call(cmd, apiKey, secretKey, false, ApiConstants.DELETE_SNAPSHOT_POLICIES_RESPONSE, null, CloudStackInfoResponse.class); +======= + return _client.call(cmd, apiKey, secretKey, false, ApiConstants.DELETE_SNAPSHOT_POLICIES_RESPONSE, ApiConstants.SNAPSHOT, CloudStackInfoResponse.class); +>>>>>>> 6472e7b... Now really adding the renamed files! } /** @@ -1947,6 +1955,7 @@ public class CloudStackApi { * @param zoneId * @param account * @param domainId +<<<<<<< HEAD * @param isDefault * @param startIp * @param endIp @@ -1954,13 +1963,26 @@ public class CloudStackApi { * @param netmask * @param isShared * @param networkDomain +======= + * @param endIp + * @param gateway + * @param isDefault + * @param isShared + * @param netmask + * @param networkDomain + * @param startIp +>>>>>>> 6472e7b... Now really adding the renamed files! * @param tags * @param vlan * @return * @throws Exception */ public CloudStackNetwork createNetwork(String displayText, String name, String networkOfferingId, String zoneId, String account, String domainId, +<<<<<<< HEAD Boolean isDefault, String startIp, String endIp, String gateway, String netmask, Boolean isShared, String networkDomain, String tags, +======= + String endIp, String gateway, Boolean isDefault, Boolean isShared, String netmask, String networkDomain, String startIp, String tags, +>>>>>>> 6472e7b... Now really adding the renamed files! String vlan) throws Exception { CloudStackCommand cmd = new CloudStackCommand(ApiConstants.CREATE_NETWORK); if (cmd != null) { diff --git a/awsapi/src/com/cloud/stack/models/ApiConstants.java b/awsapi/src/com/cloud/stack/models/ApiConstants.java index e8e172e2bd3..46e33de70de 100644 --- a/awsapi/src/com/cloud/stack/models/ApiConstants.java +++ b/awsapi/src/com/cloud/stack/models/ApiConstants.java @@ -283,7 +283,11 @@ public class ApiConstants { public static final String LIST_SNAPSHOT_POLICIES = "listSnapshotPolicies"; public static final String LIST_SNAPSHOT_POLICIES_RESPONSE = "listsnapshotpoliciesresponse"; public static final String LIST_SNAPSHOTS = "listSnapshots"; +<<<<<<< HEAD public static final String LIST_SNAPSHOTS_RESPONSE = "listsnapshotsresponse"; +======= + public static final String LIST_SNAPSHOTS_RESPONSE = "listsnapshotsresponsee"; +>>>>>>> 6472e7b... Now really adding the renamed files! public static final String LIST_SSH_KEY_PAIRS = "listSSHKeyPairs"; public static final String LIST_SSH_KEY_PAIRS_RESPONSE = "listsshkeypairsresponse"; public static final String LIST_TEMPLATE_PERMISSIONS = "listTemplatePermissions"; @@ -382,7 +386,11 @@ public class ApiConstants { public static final String RESTART_NETWORK = "restartNetwork"; public static final String RESTART_NETWORK_RESPONSE = "restartnetworkresponse"; public static final String REVOKE_SECURITY_GROUP_INGRESS = "revokeSecurityGroupIngress"; +<<<<<<< HEAD public static final String REVOKE_SECURITY_GROUP_INGRESS_RESPONSE = "revokesecuritygroupingress"; +======= + public static final String REVOKE_SECURITY_GROUP_INGRESS_RESPONSE = "revokesecuritygroupingressresponse"; +>>>>>>> 6472e7b... Now really adding the renamed files! public static final String ROOT_DEVICE_ID = "rootdeviceid"; public static final String ROOT_DEVICE_TYPE = "rootdevicetype"; public static final String RULE_ID = "ruleid"; diff --git a/awsapi/src/com/cloud/stack/models/CloudStackIngressRule.java b/awsapi/src/com/cloud/stack/models/CloudStackIngressRule.java index 4f54114e8fc..4af4d0e3908 100644 --- a/awsapi/src/com/cloud/stack/models/CloudStackIngressRule.java +++ b/awsapi/src/com/cloud/stack/models/CloudStackIngressRule.java @@ -20,7 +20,11 @@ import com.google.gson.annotations.SerializedName; public class CloudStackIngressRule { @SerializedName(ApiConstants.RULE_ID) +<<<<<<< HEAD private String ruleId; +======= + private Long ruleId; +>>>>>>> 6472e7b... Now really adding the renamed files! @SerializedName(ApiConstants.PROTOCOL) private String protocol; @@ -49,7 +53,11 @@ public class CloudStackIngressRule { public CloudStackIngressRule() { } +<<<<<<< HEAD public String getRuleId() { +======= + public Long getRuleId() { +>>>>>>> 6472e7b... Now really adding the renamed files! return ruleId; } diff --git a/awsapi/src/com/cloud/stack/models/CloudStackNic.java b/awsapi/src/com/cloud/stack/models/CloudStackNic.java index f6156eec2d9..219b21a4b0d 100644 --- a/awsapi/src/com/cloud/stack/models/CloudStackNic.java +++ b/awsapi/src/com/cloud/stack/models/CloudStackNic.java @@ -20,7 +20,11 @@ import com.google.gson.annotations.SerializedName; public class CloudStackNic { @SerializedName(ApiConstants.ID) +<<<<<<< HEAD private String id; +======= + private Long id; +>>>>>>> 6472e7b... Now really adding the renamed files! @SerializedName(ApiConstants.BROADCAST_URI) private String broadcastUri; @@ -44,7 +48,11 @@ public class CloudStackNic { private String netmask; @SerializedName(ApiConstants.NETWORK_ID) +<<<<<<< HEAD private String networkid; +======= + private Long networkid; +>>>>>>> 6472e7b... Now really adding the renamed files! @SerializedName(ApiConstants.TRAFFIC_TYPE) private String trafficType; @@ -55,11 +63,19 @@ public class CloudStackNic { public CloudStackNic() { } +<<<<<<< HEAD public String getId() { return id; } public String getNetworkid() { +======= + public Long getId() { + return id; + } + + public Long getNetworkid() { +>>>>>>> 6472e7b... Now really adding the renamed files! return networkid; } diff --git a/awsapi/src/com/cloud/stack/models/CloudStackResourceLimit.java b/awsapi/src/com/cloud/stack/models/CloudStackResourceLimit.java index 1f9bd677d6c..6edaa969868 100644 --- a/awsapi/src/com/cloud/stack/models/CloudStackResourceLimit.java +++ b/awsapi/src/com/cloud/stack/models/CloudStackResourceLimit.java @@ -21,7 +21,11 @@ public class CloudStackResourceLimit { @SerializedName(ApiConstants.ACCOUNT) private String accountName; @SerializedName(ApiConstants.DOMAIN_ID) +<<<<<<< HEAD private String domainId; +======= + private Long domainId; +>>>>>>> 6472e7b... Now really adding the renamed files! @SerializedName(ApiConstants.DOMAIN) private String domainName; @SerializedName(ApiConstants.RESOURCE_TYPE) @@ -37,9 +41,15 @@ public class CloudStackResourceLimit { return accountName; } +<<<<<<< HEAD public String getDomainId() { return domainId; } +======= + public Long getDomainId() { + return domainId; + } +>>>>>>> 6472e7b... Now really adding the renamed files! public String getDomainName() { return domainName; diff --git a/awsapi/src/com/cloud/stack/models/CloudStackSecurityGroupIngress.java b/awsapi/src/com/cloud/stack/models/CloudStackSecurityGroupIngress.java index f4d4291637a..fdcc4686f4d 100644 --- a/awsapi/src/com/cloud/stack/models/CloudStackSecurityGroupIngress.java +++ b/awsapi/src/com/cloud/stack/models/CloudStackSecurityGroupIngress.java @@ -36,7 +36,11 @@ public class CloudStackSecurityGroupIngress { @SerializedName(ApiConstants.PROTOCOL) private String protocol; @SerializedName(ApiConstants.RULE_ID) +<<<<<<< HEAD private String ruleId; +======= + private Long ruleId; +>>>>>>> 6472e7b... Now really adding the renamed files! @SerializedName(ApiConstants.SECURITY_GROUP_NAME) private String securityGroupName; @SerializedName(ApiConstants.START_PORT) @@ -102,7 +106,11 @@ public class CloudStackSecurityGroupIngress { /** * @return the ruleId */ +<<<<<<< HEAD public String getRuleId() { +======= + public Long getRuleId() { +>>>>>>> 6472e7b... Now really adding the renamed files! return ruleId; } diff --git a/awsapi/src/com/cloud/stack/models/CloudStackServiceOffering.java b/awsapi/src/com/cloud/stack/models/CloudStackServiceOffering.java index 5b2e5028179..2cf0e34d3b0 100644 --- a/awsapi/src/com/cloud/stack/models/CloudStackServiceOffering.java +++ b/awsapi/src/com/cloud/stack/models/CloudStackServiceOffering.java @@ -23,8 +23,13 @@ import com.google.gson.annotations.SerializedName; * */ public class CloudStackServiceOffering { +<<<<<<< HEAD @SerializedName(ApiConstants.ID) private String id; +======= + @SerializedName(ApiConstants.ID) + private Long id; +>>>>>>> 6472e7b... Now really adding the renamed files! @SerializedName(ApiConstants.CPU_NUMBER) private Long cpuNumber; @SerializedName(ApiConstants.CPU_SPEED) @@ -38,7 +43,11 @@ public class CloudStackServiceOffering { @SerializedName(ApiConstants.DOMAIN) private String domain; @SerializedName(ApiConstants.DOMAIN_ID) +<<<<<<< HEAD private String domainId; +======= + private Long domainId; +>>>>>>> 6472e7b... Now really adding the renamed files! @SerializedName(ApiConstants.HOST_TAGS) private String hostTags; @SerializedName(ApiConstants.IS_SYSTEM) @@ -49,7 +58,11 @@ public class CloudStackServiceOffering { private Long memory; @SerializedName(ApiConstants.NAME) private String name; +<<<<<<< HEAD @SerializedName(ApiConstants.OFFER_HA) +======= + @SerializedName(ApiConstants.OFFER_HA) +>>>>>>> 6472e7b... Now really adding the renamed files! private Boolean offerHa; @SerializedName(ApiConstants.STORAGE_TYPE) private String storageType; @@ -68,6 +81,7 @@ public class CloudStackServiceOffering { /** * @return the id */ +<<<<<<< HEAD public String getId() { return id; } @@ -75,6 +89,11 @@ public class CloudStackServiceOffering { public void setId(String id) { this.id = id; } +======= + public Long getId() { + return id; + } +>>>>>>> 6472e7b... Now really adding the renamed files! /** * @return the cpuNumber @@ -121,6 +140,7 @@ public class CloudStackServiceOffering { /** * @return the domainId */ +<<<<<<< HEAD public String getDomainId() { return domainId; } @@ -130,6 +150,13 @@ public class CloudStackServiceOffering { } /** +======= + public Long getDomainId() { + return domainId; + } + + /** +>>>>>>> 6472e7b... Now really adding the renamed files! * @return the hostTags */ public String getHostTags() { @@ -163,11 +190,15 @@ public class CloudStackServiceOffering { public String getName() { return name; } +<<<<<<< HEAD public void setName(String name) { this.name = name; } +======= + +>>>>>>> 6472e7b... Now really adding the renamed files! /** * @return the offerHa */ diff --git a/awsapi/wscript b/awsapi/wscript index 873840e5d34..47dcfce7a56 100644 --- a/awsapi/wscript +++ b/awsapi/wscript @@ -3,7 +3,11 @@ # the following two variables are used by the target "waf dist" # if you change 'em here, you need to change it also in cloud.spec, add a %changelog entry there, and add an entry in debian/changelog +<<<<<<< HEAD VERSION = '1.0.8' +======= +VERSION = '1.0.0' +>>>>>>> 6472e7b... Now really adding the renamed files! APPNAME = 'cloud-bridge' import shutil,os,glob