I have one service layer class which takes in a userId and add the userId to an arraylist in the Lobby object.I need to perform Integration test for this functionality. But somehow the code is not returning the updated arraylist to the test class. In service layer its working fine but when asserting the arraylist updated size, its failing.
Test module -
#BeforeEach
public void setupLobby(){
testUser = new User();
testUser.setPassword("testName");
testUser.setUsername("testUsername");
testUser = userService.createUser(testUser);
lobbyTest = new Lobby();
lobbyTest.setName("testLobby");
lobbyTest.setHostPlayerId(testUser.getId());
lobbyId = lobbyService.createLobby(lobbyTest);
}
#Test
public void addUserToLobby(){
System.out.println("before ->"+lobbyTest.getPlayerIds().size());
User newUser = new User();
newUser.setUsername("user2");
newUser.setPassword("password");
newUser = userService.createUser(newUser);
System.out.println("new user ->"+newUser.getId());
lobbyService.addPlayerToLobby(lobbyTest.getId(),newUser.getId());
System.out.println("after->"+lobbyTest.getPlayerIds().size());
assertEquals(lobbyTest.getPlayerIds().size(),2);
}
Service method which I need to test
public void addPlayerToLobby(long id, long userId){
Lobby lobby = getLobby(id);
System.out.println("service ->"+lobby.getId()+" "+lobby.getPlayerIds().size());
if(lobby.getStatus()==1){
throw new LobbyException("Game is in progress. You can't join lobby in the middle of the game. Please try later");
}
//Checking if the user exists before adding the user to lobby
try {
userRepository.findById(userId);
} catch (Exception e) {
throw new LobbyException(String.format("User with id: %d doesn't exist", userId));
}
String baseErrorMessage = "The lobby cannot have more than 7 player. Please join different lobby";
System.out.println("service2->"+lobby.getId()+" "+lobby.getPlayerIds().size());
//Size of lobby is limited to maximum of 7 players.
if(lobby.getPlayerIds().size()>7){
throw new LobbyException(baseErrorMessage);
}
//Player should be unique in the lobby
if(lobby.getPlayerIds().contains(userId)){
baseErrorMessage = "Player already exists in the lobby";
throw new LobbyException(baseErrorMessage);
}
lobby.getPlayerIds().add(userId);
saveOrUpdate(lobby);
System.out.println("service3->"+lobby.getId()+" "+lobby.getPlayerIds().size());
}
public Lobby getLobby(Long id) {
Optional<Lobby> optionalLobby = lobbyRepository.findById(id);
if (!optionalLobby.isPresent()) {
throw new LobbyException(String.format("Could not find lobby with id %d.", id));
}
return optionalLobby.get();
}
public void saveOrUpdate(Lobby updateLobby){
lobbyRepository.save(updateLobby);
lobbyRepository.flush();
System.out.println("service method ->"+updateLobby.getId()+" "+updateLobby.getPlayerIds().size());
}
For my testing I have put some print statement which clearly shows that its updating the arraylist in service layer but its not replicated in integration test method.
before ->1
new user ->3
service ->2 1
service2->2 1
service method ->2 2
service3->2 2
after->1
I am unable to get the issue. If there is some reference issue with the object?
I'd need to see the full source code to be sure, but it seems the Lobby object returned at:
Lobby lobby = getLobby(id);
is not the same object as the Lobby you set up in your test.
You can confirm that by checking the object signature (toString()), their Hex codes are likely different.
Related
I am practicing Java and Spring Boot.
Actually my idea is if we send json delete request means it should change details in the database as inactive instead of deleting that data.
for Example if I want to delete the student record. Base on student ID as 1 means it should change the student status as inactive instead of deleting that record.
In spring boot controller I have a delete method.
Codes are below for your understanding:
Controller:
#DeleteMapping("v1/student/delete/{id}")
public ResponseEntity<String> deleteStudentDetails(#PathVariable("id") Integer getId) {
studentService.deleteStudentdetails(getId);
return new ResponseEntity<>("STUDENT RECORD HAS BEEN DELETED !!!", HttpStatus.OK);
}
studentService = is a service class which sending the information from controller to service.
deleteStudentdetails = is a method in service class.
Service class method
public void deleteStudentdetails(Integer getId) {
Optional<StudentDetails> studentIdDetails = studentRepo.findById(getId); // getting info from DB
StudentDetails studentIsdetail = studentIdDetails.get();
if (studentIsdetail.getActive() == false) {
throw new RuntimeException("Student is Already inActive!!");
}
studentIsdetail.setActive(false); // Here I want to change the Active Status from True to false
}
Here I am changing the values in the Database by retrieving the student ID which is already existing in the DB.
STUDENT_ID ACTIVE BOARD_ID
60 TRUE STATEBOARD
116 TRUE STATEBOARD //here want to change the status as False
120 FALSE STATEBOARD
You never save studentIsdetail into the database after modifying.
So just add studentRepo.save(studentIsdetail); after calling studentIsdetail.setActive(false); and it should work:
public void deleteStudentdetails(Integer getId) {
Optional<StudentDetails> studentIdDetails = studentRepo.findById(getId); // getting info from DB
StudentDetails studentIsdetail = studentIdDetails.get();
if (!studentIsdetail.getActive()) {
throw new RuntimeException("Student is Already inActive!!");
}
studentIsdetail.setActive(false);
studentRepo.save(studentIsdetail);
}
And I recommend that you check if you get a result to avoid exceptions:
public void deleteStudentdetails(Integer getId) {
Optional<StudentDetails> studentIdDetails = studentRepo.findById(getId); // getting info from DB
if (studentIsdetail.isEmpty()) {
// handle e.g. throw exception or just return (with return:)
return;
}
StudentDetails studentIsdetail = studentIdDetails.get();
if (!studentIsdetail.getActive()) {
throw new RuntimeException("Student is Already inActive!!");
}
studentIsdetail.setActive(false);
studentRepo.save(studentIsdetail);
}
For this you can also use Optional#ifPresent:
public void deleteStudentdetails(Integer getId) {
Optional<StudentDetails> studentIdDetails = studentRepo.findById(getId); // getting info from DB
studentIdDetails.ifPresent((studentIsdetail) -> {
if (!studentIsdetail.getActive()) {
throw new RuntimeException("Student is Already inActive!!");
}
studentIsdetail.setActive(false);
studentRepo.save(studentIsdetail);
});
}
I am creating a new state in the flow and then I am trying to consume the state by using reference input. But every time I see in the result as unconsumed state, though I was providing the reference state in the transaction's input.
public SignedTransaction call() throws FlowException {
//------------------------------------------------------------------------------------------------------------
// STEP-1:
// FIRST FLOW MUST CREATE THE NEW STATE WHICH HAS NO INPUT ( THIS WILL CREATE NEW RECORD-ANCHOR WITH LINEARID )
//
//------------------------------------------------------------------------------------------------------------
// We retrieve the notary identity from the network map.
Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);
// We create the transaction components.
AnchorState outputState = new
AnchorState(ownerId,contentHash,description,classid,timestamp,expiry, getOurIdentity(), otherParty,new UniqueIdentifier());
//required signers
List<PublicKey> requiredSigners = Arrays.asList(getOurIdentity().getOwningKey(),otherParty.getOwningKey());
//send create command with required signer signatures as below
Command command = new Command<>(new AnchorStateContract.Commands.CreateRecAnchorCmd(), requiredSigners);
// We create a transaction builder and add the components.
TransactionBuilder txBuilder = new TransactionBuilder(notary)
.addOutputState(outputState, AnchorStateContract.ID)
.addCommand(command);
// Verifying the transaction.
txBuilder.verify(getServiceHub());
// Signing the transaction.
SignedTransaction signedTx = getServiceHub().signInitialTransaction(txBuilder);
// Creating a session with the other party.
FlowSession otherPartySession = initiateFlow(otherParty);
// Obtaining the counterparty's signature.
SignedTransaction fullySignedTx = subFlow(new CollectSignaturesFlow(
signedTx, Arrays.asList(otherPartySession), CollectSignaturesFlow.Companion.tracker()));
//notarized transaction
SignedTransaction notraizedtransaction = subFlow(new FinalityFlow(fullySignedTx, otherPartySession));
//------------------------------------------------------------------------------------------------------------
// STEP-2:
// SINCE NOW WE HAVE A NEW UNCONSUMED RECORD-ANCHOR SO WE MUST MAKE IT CONSUMED ( BY USING THE PREVIOUS OUTPUT AS AN INPUT)
//
//------------------------------------------------------------------------------------------------------------
StateAndRef oldStateref = getServiceHub().toStateAndRef(new StateRef(notraizedtransaction.getId(),0));
Command storeCommand = new Command<>(new AnchorStateContract.Commands.ApproveRecAnchorCmd(), requiredSigners);
TransactionBuilder txBuilder2 = new TransactionBuilder(notary)
.addInputState(oldStateref)
.addOutputState(outputState, AnchorStateContract.ID)
.addCommand(storeCommand);
txBuilder2.verify(getServiceHub());
// signing
SignedTransaction signedTx2 = getServiceHub().signInitialTransaction(txBuilder2);
// Creating a session with the other party.
FlowSession otherPartySession2 = initiateFlow(otherParty);
// Finalising the transaction.
SignedTransaction fullySignedTx2 = subFlow(new CollectSignaturesFlow(
signedTx2, Arrays.asList(otherPartySession2), CollectSignaturesFlow.Companion.tracker()));
//notarized transaction
return subFlow(new FinalityFlow(fullySignedTx2, otherPartySession2));
}
In my flow initiator class I am first creating new state of a hash which I am calling as AnchorState. This state is coming from one of the participants and then it requests to the other participant to sign. afterward the signed record is stored in the ledger but its reference used as an input for a new state change, I simply want to make this state as consumed rather than unconsumed.
The responding flow class of participant B is as below
public SignedTransaction call() throws FlowException
{
//this class is used inside call function for the verification purposes before signed by this party
class SignTxFlow extends SignTransactionFlow
{
private SignTxFlow(FlowSession otherPartySession) {
super(otherPartySession);
}
#Override
protected void checkTransaction(SignedTransaction stx) {
requireThat(require -> {
ContractState output = stx.getTx().getOutputs().get(0).getData();
require.using("This must be an AnchorState transaction.", output instanceof AnchorState);
AnchorState state = (AnchorState) output;
require.using("The AnchorState's value should be more than 6 characters", state.getContentHash().length() > 6);
return null;
});
}
}
SecureHash expectedTxId = subFlow(new SignTxFlow(otherPartySession)).getId();
return subFlow(new ReceiveFinalityFlow(otherPartySession, expectedTxId));
}
This flow successfully runs and returns me unique id for the transaction but I tried everything and could not found how to change the state from unconsumed to consumed?
AFTER FIX
I realized that the vaultQuery on the CordaOS by default returns unconsumed state. Which is now clear why I was not able to get the consumed state in the first place. One more issue which I found, was lack of resources in CORDA for java though I found many kotlin based answers for a transaction with "creation and consumption" in single workflow however converting them into JAVA required some efforts.
Kotlin Based answer
Some differences I observed between Java and Kotlin approach
1) When I have tried to use the same session in my second transaction which was used in the first transaction then I get this error
java.util.concurrent.ExecutionException: net.corda.core.flows.UnexpectedFlowEndException: Tried to access ended session SessionId(toLong=1984916257986245538) with empty buffer
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
at net.corda.core.internal.concurrent.CordaFutureImpl.get(CordaFutureImpl.kt)
Which means we have to create new session every time for the new transaction regardless if they are in the single workflow.
2) As I understood by looking at the Kotlin solution that we don't need to add output in the transaction if we just want to make it consumed. However when I do not add an output state in the second transaction then I get the following error which means even for the consumed state I must add the same output inside the transaction. Otherwise, the following error will get erupted again.
ava.util.concurrent.ExecutionException: net.corda.core.flows.UnexpectedFlowEndException: Counter-flow errored
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
at net.corda.core.internal.concurrent.CordaFutureImpl.get(CordaFutureImpl.kt)
at com.etasjil.Client.testFlow(Client.java:92)
So it is clear that unlike kotlin, in java we need to explicitly add the output state and new session if we want to create and consume a state within same workflow.
Note: Since this is a new learning curve for me therefore, if I made any mistake in the above realization then kindly correct me. This answer could be good for the new comers in Corda who wants to code in Java rather than Kotlin.
State
#BelongsToContract(AnchorStateContract.class)
public class AnchorState implements LinearState {
public String ownerId,contentHash,description,classid,timestamp,expiry;
public Party initiatorParty, otherParty;
public UniqueIdentifier linearId;
#Override
public List<AbstractParty> getParticipants() {
return Arrays.asList(initiatorParty, otherParty);
}
public AnchorState() {
}
#ConstructorForDeserialization
public AnchorState(String ownerId, String contentHash, String description, String classid, String timestamp, String expiry, Party initiatorParty, Party otherParty, UniqueIdentifier linearId) {
this.ownerId = ownerId;
this.contentHash = contentHash;
this.description = description;
this.classid = classid;
this.timestamp = timestamp;
this.expiry = expiry;
this.initiatorParty = initiatorParty;
this.otherParty = otherParty;
this.linearId = linearId;
}
...
FlowTest case
...
...
#Test
public void test1() {
Future data = a.startFlow(new Initiator("Owner1", "1234567", "Description", "c1", Instant.now().toString(), Instant.MAX.toString(), b.getInfo().getLegalIdentities().get(0).getName().toString()));
network.runNetwork();
try {
System.out.println(data.get());
}catch (Exception e){
System.out.println(e.getMessage());
}
QueryCriteria.VaultQueryCriteria criteria1 = new QueryCriteria.VaultQueryCriteria(Vault.StateStatus.CONSUMED);
Vault.Page<AnchorState> results1 = a.getServices().getVaultService().queryBy(AnchorState.class, criteria1);
System.out.println("--------------------- "+ results1.getStates().size());
QueryCriteria.VaultQueryCriteria criteria2 = new QueryCriteria.VaultQueryCriteria(Vault.StateStatus.ALL);
Vault.Page<AnchorState> results2 = a.getServices().getVaultService().queryBy(AnchorState.class, criteria2);
System.out.println("--------------------- "+ results2.getStates().size());
QueryCriteria.VaultQueryCriteria criteria3 = new QueryCriteria.VaultQueryCriteria(Vault.StateStatus.CONSUMED);
Vault.Page<AnchorState> results3 = b.getServices().getVaultService().queryBy(AnchorState.class, criteria3);
System.out.println("--------------------- "+ results3.getStates().size());
QueryCriteria.VaultQueryCriteria criteria4 = new QueryCriteria.VaultQueryCriteria(Vault.StateStatus.ALL);
Vault.Page<AnchorState> results4 = b.getServices().getVaultService().queryBy(AnchorState.class, criteria4);
System.out.println("--------------------- "+ results4.getStates().size());
}
I got 1,2,1,2 as the outputs which tells 1 consumed state in node a & b, totally 2 states in node a and b(1 consumed and 1 unconsumed).
I have entity for reporting. I wonna know who filled up report. I would like to put id of user from session to form class.
I've tried already methods like: bind, fill; but no working solution found.
Ofcorse I mean form class: play.data.Form.form
How can I achive this?
Please help.
Here is my approach (when I wrote this Post):
static Form<Registry> modelForm = form(Registry.class);
Registry registry = new Registry();
registry.creationUser = User.getCurrentUser();
registry.test="tt";
modelForm.fill(registry);
modelForm.bind(data, allowedFields)
My submit method
#Transactional
public static Result submit() {
modelForm = modelForm.bindFromRequest();
if (modelForm.hasErrors()) {
return badRequest(views.html.Registry.form.render(modelForm));
} else {
modelForm.get();
}
registry.creationUser = User.getCurrentUser();
modelForm.fill(registry);
if (modelForm.hasErrors()) {
Logger.debug(modelForm.toString());
return badRequest(views.html.Registry.form.render(modelForm));
} else {
modelForm.get().toDataBase();
toLog("success", "Succefully added new Report");
flash("success", "Pomyślnie dodano.");
return redirect(routes.Index.index());
}
}
Let's say you have a Report model like:
public Date date;
public User user;
public String message;
You need to create and fill an object first (without saving to DB!) and then fill the form with it, like:
Report report = new Report(); // constructors params are welcome here
report.user = loggedUser;
report.date = new Date();
Form<Report> reportForm = Form.form(Report.class).fill(report);
// OR
Form<Report> reportForm = Form.form(Report.class);
reportForm = reportForm().fill(report);
// NOT
Form<Report> reportForm = Form.form(Report.class);
reportForm().fill(report); // Wrong!
return ok(reportCreatingView.render(reportForm));
Edit: You don't need to fill User data at first step, as actually you can add it after binding, you have too much lines in your submit() action, keep it simple :)
public static Result submit() {
User user = User.getCurrentUser();
if (user == null) return unauthorized("You must log in");
modelForm = modelForm.bindFromRequest();
if (modelForm.hasErrors()) {
return badRequest(views.html.Registry.form.render(modelForm));
}
// At this point you have a logged User obj which is not null,
// you have modelForm without errors (checked previously)
// so you need to only add the user to form and save it.
Registry registry = modelForm.get();
registry.creationUser = user;
registry.save();
flash("success", "Twój log został zapisany w bazie.");
return redirect(routes.Index.index());
}
I have an android app in which I use greenDAO to model my database. I have an easy scenario but I don't understand how I can make it work. I've followed the documentation but I must be missing something.
I have 3 entities: User, Picture and Address. A User has Pictures and Addresses. My getters for Picture and Address always return null.
userEntity.getPicture(); -> returns null
userEntity.getAddress(); -> returns null
Here is my GreenDAO setup
Entity userEntity = schema.addEntity("User");
userEntity.addIdProperty();
userEntity.addStringProperty("firstName");
userEntity.addStringProperty("lastName");
Entity picture = schema.addEntity("Picture");
picture.addIdProperty();
picture.addByteArrayProperty("image");
picture.addStringProperty("imageName");
Entity address = schema.addEntity("Address");
address.addIdProperty();
address.addStringProperty("street");
address.addIntProperty("houseNumber");
address.addIntProperty("zipcode");
address.addStringProperty("city");
// a user can have multiple pictures but a picture is connected to one user
Property pictureIdProperty = picture.addLongProperty("userId").getProperty();
picture.addToOne(userEntity, pictureIdProperty).setName("user");
userEntity.addToMany(picture, pictureIdProperty).setName("picture");
// a user can have multiple addresses but an address is only connected to one user
Property addressIdProperty = address.addLongProperty("userId").getProperty();
address.addToOne(userEntity, addressIdProperty).setName("user");
userEntity.addToMany(address, addressIdProperty).setName("address");
Here is my testclass to test the relations
DevOpenHelper helper = new DaoMaster.DevOpenHelper(getApplication(), "relation_test_db", null);
SQLiteDatabase db = helper.getWritableDatabase();
DaoMaster daoMaster = new DaoMaster(db);
this.daoSession = daoMaster.newSession();
UserDao userDao = this.daoSession.getUserDao();
PictureDao pictureDao = this.daoSession.getPictureDao();
AddressDao addressDao = this.daoSession.getAddressDao();
// clear all data
userDao.deleteAll();
pictureDao.deleteAll();
addressDao.deleteAll();
/**
* create data
*/
User bill = new User(null);
bill.setFirstName("Bill");
bill.setLastName("Murray");
Picture billsPicture = new Picture(null);
billsPicture.setImage("BillsExamplePictureByteArray".getBytes());
billsPicture.setImageName("BillsPictureName");
Address billsAddress = new Address(null);
billsAddress.setStreet("BillsStreet");
billsAddress.setHouseNumber(42);
billsAddress.setZipcode(12345);
billsAddress.setCity("Wilmette");
billsPicture.setUser(bill);
billsAddress.setUser(bill);
userDao.insert(bill);
pictureDao.insert(billsPicture);
addressDao.insert(billsAddress);
User user = userDao.queryBuilder().list().get(0);
ArrayList<Picture> billsPictureList = (ArrayList<Picture>) user.getPicture();
ArrayList<Address> billsAddressList = (ArrayList<Address>) user.getAddress();
if (billsPictureList == null || billsPictureList.size() == 0) {
// contact Markus
Toast.makeText(this, "Contact Stackoverflow", Toast.LENGTH_SHORT).show();
return;
}
if (billsAddressList == null || billsAddressList.size() == 0) {
// contact Markus
Toast.makeText(this, "Contact Stackoverflow", Toast.LENGTH_SHORT).show();
return;
}
Emanuel,
I am facing some similar issues when trying to save objects with 1-to-1 relations.
After spending pretty enough time with greenDAO I have found, that all "relational" objects should have appropriate mapping IDs of their "parents" before being saved to DB.
So I may suggest, that if you take a look at setUser methods of your generated Picture and Address entities, you will see something like:
public void setUser(User user) {
synchronized (this) {
this.user = user;
userId = user == null ? null : user.getId();
user__resolvedKey = userId;
}
}
Crucial is userId = user == null ? null : user.getId();
There are race conditions, as your created User object will not get ID until it is actually saved to DB. And if it does not have ID, there is a chance, that setUser of its relational entities will not work normally.
In your case you may try to change save sequence to:
//1. Save user to DB, this will give it ID
userDao.insert(bill);
//2. Set user entity with ID to its relational entities
billsPicture.setUser(bill);
billsAddress.setUser(bill);
//3. Save relational entities
pictureDao.insert(billsPicture);
addressDao.insert(billsAddress);
Hope my answer will be helpful to you.
I am new to this OpenFire and asmack, i want the user to have a functionality of Multi Users Chatting so i searched around and i found MUC i have implemented this for creating a room and sending invitation to other users these works, other user receives the invitation but the other user is not able to join the room.
I am doing this on other user invitation receiving
Here connection is the connection of this user and room is the room name that we getting in invitation.
MultiUserChat muc3 = new MultiUserChat(connection,room);
muc3.join("testbot3");
testbot3 is just some random name.
But this throws 404 error.
Do i need to join the user before sending the invitation i.e if A user sending invitation to B , before invitation sent do A needs to join these users by default to room and then it depends on B to decline or just keep quite.
What i am doing is B receives invitation from A in that InvitationListner of B i am trying to join with the above code.
I have been trying for long now i am not sure what is going wrong, some one can give a sample code of how to do this it would be great help for me.
Thanks
Here is more information on my issue
As i go and check on Openfire i can see the room created by the user and he has been added himself as an owner so i dont think so it would be an issue with room getting created.
May be this can be an issue with room getting locked, as i have read through the room is locked when the room is not completely created , i guess this is an issue with form filling when we create the room, i am not filling in the password in the form can this be an issue ?
Please see the following code below inside the handler i am calling a method "checkInvitation" which does the same as above code posted still i get 404. Can you please tell me what i wrong in my code.
Do the nickname that needs to be added can be anything or it needs to something user specific ?
public void createChatroom(){
MultiUserChat muc = null;
try {
muc = new MultiUserChat(connection, "myroom#conference.localhost");
muc.create("testbot");
// Get the the room's configuration form
Form form = muc.getConfigurationForm();
// Create a new form to submit based on the original form
Form submitForm = form.createAnswerForm();
// Add default answers to the form to submit
for (Iterator fields = form.getFields(); fields.hasNext();) {
FormField field = (FormField) fields.next();
if (!FormField.TYPE_HIDDEN.equals(field.getType()) && field.getVariable() != null) {
// Sets the default value as the answer
submitForm.setDefaultAnswer(field.getVariable());
}
}
// Sets the new owner of the room
List owners = new ArrayList();
owners.add("admin#localhost");
submitForm.setAnswer("muc#roomconfig_roomowners", owners);
// Send the completed form (with default values) to the server to configure the room
muc.sendConfigurationForm(submitForm);
muc.join("d");
muc.invite("b#localhost", "Meet me in this excellent room");
muc.addInvitationRejectionListener(new InvitationRejectionListener() {
public void invitationDeclined(String invitee, String reason) {
// Do whatever you need here...
System.out.println("Initee "+invitee+" reason"+reason);
}
});
} catch (XMPPException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void setConnection(XMPPConnection connection) {
this.connection = connection;
if (connection != null) {
// Add a packet listener to get messages sent to us
PacketFilter filter = new MessageTypeFilter(Message.Type.chat);
connection.addPacketListener(new PacketListener() {
public void processPacket(Packet packet) {
Message message = (Message) packet;
if (message.getBody() != null) {
String fromName = StringUtils.parseBareAddress(message
.getFrom());
Log.i("XMPPClient", "Got text [" + message.getBody()
+ "] from [" + fromName + "]");
messages.add(fromName + ":");
messages.add(message.getBody());
// Add the incoming message to the list view
mHandler.post(new Runnable() {
public void run() {
setListAdapter();
checkInvitation();
}
});
}
}
}, filter);
mHandler.post(new Runnable() {
public void run() {
checkInvitation();
}
});
}
}
The 404 error indicates that:
404 error can occur if the room does not exist or is locked
So, ensure that your room is not locked or existed! The code below is how I join the room when there's an in-comming invitation:
private void setChatRoomInvitationListener() {
MultiUserChat.addInvitationListener(mXmppConnection,
new InvitationListener() {
#Override
public void invitationReceived(Connection connection,
String room, String inviter, String reason,
String unKnown, Message message) {
//MultiUserChat.decline(mXmppConnection, room, inviter,
// "Don't bother me right now");
// MultiUserChat.decline(mXmppConnection, room, inviter,
// "Don't bother me right now");
try {
muc.join("test-nick-name");
Log.e("abc","join room successfully");
muc.sendMessage("I joined this room!! Bravo!!");
} catch (XMPPException e) {
e.printStackTrace();
Log.e("abc","join room failed!");
}
}
});
}
Hope this helps your error!
Edit:this is how I config the room:
/*
* Create room
*/
muc.create(roomName);
// muc.sendConfigurationForm(new Form(Form.TYPE_SUBMIT));
Form form = muc.getConfigurationForm();
Form submitForm = form.createAnswerForm();
for (Iterator fields = form.getFields(); fields.hasNext();) {
FormField field = (FormField) fields.next();
if (!FormField.TYPE_HIDDEN.equals(field.getType())
&& field.getVariable() != null) {
show("field: " + field.getVariable());
// Sets the default value as the answer
submitForm.setDefaultAnswer(field.getVariable());
}
}
List<String> owners = new ArrayList<String>();
owners.add(DataConfig.USERNAME + "#" + DataConfig.SERVICE);
submitForm.setAnswer("muc#roomconfig_roomowners", owners);
submitForm.setAnswer("muc#roomconfig_roomname", roomName);
submitForm.setAnswer("muc#roomconfig_persistentroom", true);
muc.sendConfigurationForm(submitForm);
// submitForm.
show("created room!");
muc.addMessageListener(new PacketListener() {
#Override
public void processPacket(Packet packet) {
show(packet.toXML());
Message mess = (Message) packet;
showMessageToUI(mess.getFrom() + ": " + mess.getBody());
}
});
With this cofiguration, I can join a room easily without password.
You may use the code snippet to join the chat:
public void joinMultiUserChatRoom(String userName, String roomName) {
// Get the MultiUserChatManager
MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
// Create a MultiUserChat using an XMPPConnection for a room
MultiUserChat multiUserChat = manager.getMultiUserChat(roomName + "#conference.localhost");
DiscussionHistory history = new DiscussionHistory();
history.setMaxStanzas(-1);
try {
multiUserChat.join(userName, "", history, connection.getPacketReplyTimeout());
} catch (Exception e) {
e.printStackTrace();
}
}
Invite a friend:
/**
* Invites another user to this room.
*
* #param userAddress the address of the user to invite to the room.(one
* may also invite users not on their contact list).
* #param reason a reason, subject, or welcome message that would tell
* the the user why they are being invited.
*/
public void invite(String userAddress, String reason)
{
multiUserChat.invite(userAddress, reason);
}