We are building a new experience for our SmartBear Community.
This site is now read-only. You can still browse and search as usual. Learn More

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

  • hairyone's avatar
    hairyone
    New Contributor
    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();
    }