Forum Discussion

hairyone's avatar
hairyone
New Contributor
15 years ago

Calling AMF service with response from prior request

Hi all,

It's been a while since I last used SoapUI (3.6.1 Build dist-111-2010-10-18) and I'm pleased to see that AMF support has been added.

Here's my problem.

I have a TestStep that creates a new user by calling userService.createOrUpdate. I have made a jar of the relevant classes and dropped it into SOAPUI/bin/ext. With the following script it works fine and the user is created.


@Transactional
@Secured("ROLE_ADMIN")
public void createOrUpdate(User user) throws Exception
{
if (user.getCompany()== null) {
user.setCompany(companyDAO.get(1));
}

userDAO.createOrUpdate(user);

String password = user.getPassword();
Object salt = saltSource.getSalt(user);

user.setPassword(passwordEncoder.encodePassword(password,salt));
userDAO.merge(user);
}



import com.twoh.dto.User
import com.twoh.dto.Company

def u = new User()
def c = new Company()

// Set up the User.Company only the id is required
// when adding a user
c.id = 1

// Set up the new User mandatory fields
u.id = 0
u.username = "soapui"
u.password = "soapui"
u.company = c

// Update the parameters value
parameters['user'] = u



I then have a TestStep that calls userService.getByUsername which returns a response like the one below (good so far ...).


@Transactional(readOnly=true)
@Secured("ROLE_USER")
public User getByUsername(String username) {
return userDAO.findByUsername(username);
}



<flex.messaging.io.amf.ASObject serialization="custom">
<unserializable-parents/>
<map>
<default>
<loadFactor>0.75</loadFactor>
<threshold>12</threshold>
</default>
<int>16</int>
<int>9</int>
<string>id</string>
<int>122</int>
<string>username</string>
<string>soapui</string>
<string>forename</string>
<null/>
<string>email</string>
<null/>
<string>initials</string>
<null/>
<string>status</string>
<null/>
<string>company</string>
<flex.messaging.io.amf.ASObject serialization="custom">
<unserializable-parents/>
<map>
<default>
<loadFactor>0.75</loadFactor>
<threshold>12</threshold>
</default>
<int>16</int>
<int>2</int>
<string>id</string>
<int>1</int>
<string>name</string>
<string>2HXX</string>
</map>
<flex.messaging.io.amf.ASObject>
<default>
<inHashCode>false</inHashCode>
<inToString>false</inToString>
<namedType>com.twoh.dto.Company</namedType>
</default>
</flex.messaging.io.amf.ASObject>
</flex.messaging.io.amf.ASObject>
<string>surname</string>
<null/>
<string>password</string>
<string>be17beaf5bc5a796ab871a76ea78f02b51e4ab17</string>
</map>
<flex.messaging.io.amf.ASObject>
<default>
<inHashCode>false</inHashCode>
<inToString>false</inToString>
<namedType>com.twoh.dto.User</namedType>
</default>
</flex.messaging.io.amf.ASObject>
</flex.messaging.io.amf.ASObject>


My problem comes when I try to call the userService.deleteUser.


@Transactional
@Secured("ROLE_USER")
public void deleteUser(User user) {
userDAO.delete(user);
}


I have tried setting the "user" property of this step to ${Retrieve user "soapui"#ResponseAsXML} and I have also tried adding the script


import flex.messaging.io.amf.client.AMFConnection;
import com.twoh.dto.User;

AMFConnection.registerAlias("com.twoh.dto.User","com.twoh.dto.User");


But I still get the error:


<flex.messaging.io.amf.ASObject serialization="custom">
<unserializable-parents/>
<map>
<default>
<loadFactor>0.75</loadFactor>
<threshold>12</threshold>
</default>
<int>16</int>
<int>4</int>
<string>message</string>
<string>Cannot invoke method &apos;deleteUser&apos;.</string>
<string>rootCause</string>
<flex.messaging.messages.ErrorMessage>
<messageId>B7B0248A-11F5-9CB9-B36F-95F0F6251F32</messageId>
<timestamp>1294863786289</timestamp>
<timeToLive>0</timeToLive>
<faultCode>Client.Message.Deserialize.InvalidType</faultCode>
<faultString>Cannot convert type java.lang.String with value &apos;&apos; to an instance of class com.twoh.dto.User</faultString>
</flex.messaging.messages.ErrorMessage>
<string>details</string>
<string>The expected argument types are (com.twoh.dto.User) but the supplied types were (java.lang.String) and converted to (null).</string>
<string>code</string>
<string>Server.ResourceUnavailable</string>
</map>
<flex.messaging.io.amf.ASObject>
<default>
<inHashCode>false</inHashCode>
<inToString>false</inToString>
</default>
</flex.messaging.io.amf.ASObject>
</flex.messaging.io.amf.ASObject>


Any thoughts on what I am doing wrong ?

1 Reply

  • OK,

    I never got a response to this and gave up for a while. Yesterday I HAD to get something working, in the end I did not use the AMF functionality at all. Following a very handy example on thenet http://aredko.blogspot.com/2010/06/testing-blazeds-remote-objects-with_06.html I came up with this as a Groovy test step and to be honest I found it much easier.

    I'm posting this as I have used SoapUI in the past for web service testing and found it to be great. Using the approach below I can now do what I want with AMF services.


    import flex.messaging.io.amf.ASObject;
    import flex.messaging.io.amf.client.AMFConnection;
    import flex.messaging.messages.CommandMessage;
    import flex.messaging.util.Base64.Encoder;
    import flex.messaging.messages.Message;

    def clientId = "soapUI." + UUID.randomUUID().toString();
    def amfConnection = new AMFConnection();
    amfConnection.instantiateTypes = false;

    try {
    amfConnection.connect(context.expand('${#Project#ServiceEndpoint}'));
    amfConnection.addAmfHeader( Message.FLEX_CLIENT_ID_HEADER, clientId );

    // First we need to authenticate
    CommandMessage commandMessage = new CommandMessage();
    String credentials = context.expand( '${#Project#AMFUsername}' ) + ":" + context.expand( '${#Project#AMFPassword}' );
    Encoder encoder = new Encoder( credentials.length() );
    encoder.encode( credentials.getBytes() );
    commandMessage.setHeader( Message.FLEX_CLIENT_ID_HEADER, clientId );
    commandMessage.setOperation( CommandMessage.LOGIN_OPERATION );
    commandMessage.setBody( encoder.drain() );
    commandMessage.setDestination( "auth" );
    amfConnection.call( null, commandMessage );

    // Try to update an existing user
    def user = amfConnection.call("userService.getByUsername", "freddy");
    log.info(user);

    def result = amfConnection.call("lockService.create", "USER", user["id"]);
    log.info(result);

    user["surname"] = "XXX";
    result = amfConnection.call("userService.createOrUpdate", user);
    log.info(result);

    result = amfConnection.call("lockService.delete", "USER", user["id"]);
    log.info(result);

    // Try to create a new user
    def company = amfConnection.call("companyService.get", 1);
    log.info(company);

    def newUser = new ASObject("com.twoh.dto.User");
    newUser["id"] = null;
    newUser["username"] = "soapui";
    newUser["company"] = company;
    log.info(newUser);

    result = amfConnection.call("userService.createOrUpdate", newUser);
    log.info(result);

    // username, oldPassword, newPassword
    result = amfConnection.call("userService.setPassword", "soapui", "", "soappass");
    log.info(result);

    // Must remember to log out
    commandMessage = new CommandMessage();
    commandMessage.setHeader( Message.FLEX_CLIENT_ID_HEADER, clientId );
    commandMessage.setOperation( CommandMessage.LOGOUT_OPERATION );
    commandMessage.setDestination( "auth" );
    amfConnection.call( null, commandMessage );

    } finally {
    amfConnection.close();
    }