Working with Smack 4.3.0 in a Multi User Chat (XEP-0045-1.21) I'm trying to find out if a room is already created or not, but I'm not sure if what I'm doing is the correct way.
I have search for it and the most relative answer to it was does MUC exist?.
Technically speaking:
Rooms are created as public and members-only by default in OpenFire 4.2.0.
All room's names are an id defined by the members name in a hash string i.e. XXXXXX029d8c36b62259d0eXXXXXXXX. This means that user A can create a room with B, C and get a groupId like the previous one, but then user B (in another device) can try to create same room (with users A,B,C), which is going to give him same groupId.
Exist a architecture layer like whatsapp, so users can leave a Group Chat and rejoin whenever they want.
What I'm doing at this moment:
#WorkerThread
public boolean isGroupChatAlreadyCreated(#NonNull final String groupId)
throws
XmppStringprepException,
XMPPException.XMPPErrorException,
MultiUserChatException.NotAMucServiceException,
SmackException.NotConnectedException,
InterruptedException,
SmackException.NoResponseException {
List<HostedRoom> hostedRooms = manager.getHostedRooms(JidCreate.domainBareFrom(serviceDomain));
for (HostedRoom hostedRoom : hostedRooms) {
if (hostedRoom.getName().equalsIgnoreCase(groupId)) {
return true;
}
}
return false;
}
where manager is MultiUserChatManager manager and serviceDomain is just a String.
so, the questions: is this right way to do it? can it be improved?
I believe the easier way is get some info about room, for example its configuration form. If nothing will be returned then it means room does not exist:
public boolean isGroupChatAlreadyCreated(#NonNull final EntityBareJid groupId)
throws
XMPPErrorException,
NotConnectedException,
InterruptedException,
NoResponseException {
MultiUserChat multiUserChat = MultiUserChatManager.getInstanceFor(connection).getMultiUserChat(groupId);
return multiUserChat.getConfigurationForm() != null;
}
More info here https://github.com/igniterealtime/Smack/blob/4.3/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java#L809
It is essentially the right way.
Ideally you simply use MulitUserChatManager.getRoomInfo(EntityBareJid). The method will return a RoomInfo if the room exists, or throw if it does not.
Your original approach can also be improved by changing the type of 'groupId' to EntityBareJid using equals() instead of equalsIgnoreCase(). And putting your groupId as Localpart of the MUC's address. So your function becomes:
public boolean isGroupChatAlreadyCreated(#NonNull final EntityBareJid groupId)
throws
XmppStringprepException,
XMPPErrorException,
NotAMucServiceException,
NotConnectedException,
InterruptedException,
NoResponseException {
List<HostedRoom> hostedRooms = manager.getHostedRooms(JidCreate.domainBareFrom(serviceDomain));
for (HostedRoom hostedRoom : hostedRooms) {
if (hostedRoom.getJid().equals(groupId)) {
return true;
}
}
return false;
}
Related
I currently code a Discord bot in Java with Discord4j. Now, I want to get the mentioned user IDs (already did that) and convert them into Member object, but I don't know how to do it.
That's my code currently:
public static void run(MessageCreateEvent event) {
if(event.getMessage().getUserMentionIds().toString() == "[]") {
Utils.sendMessageToChannel("ERROR: No User got mentioned.", event);
}
Snowflake userMentions = Snowflake.of(event.getMessage().getUserMentionIds().toString());
Member member = new Member(userMentions);
}
Discord4J does not allow the use of constructors on its entities and most objects. This is because all of the entities are built up from data from the cache and/or a rest request to discord.
To get a Member from a user ID you would do the following:
GatewayDiscordClient#getMemberById(guildId, userId).block();
If you just want the user, as Member requires the person be in the guild:
GatwayDiscordClient#getUserById(userId).block();
You can also do this reactively by (flat)mapping the Mono(s).
How to authenticate and redirect a user to his own page i.e to www.mysite.com/"user's email".
I am using the following algo which is not working...
userDB in User class:
Map<String,String> userdata=new HashMap<String,String>();
First my login process form :
#Path("/login")
#POST
#Produces(MediaType.TEXT_HTML)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public void login(
#FormParam("email") String emailc,
#FormParam("password") String pass,
#Context HttpServletResponse servletResponse
) throws IOException,RuntimeException {
User u1=new User();
pass=u1.getPassword();
emailc=u1.getEmailaddrs();
boolean checked=false;
boolean exists;
exists=u1.userdata.containsKey(emailc);
if(exists){
String mypass =u1.userdata.get(emailc);
if(mypass==pass){
checked=true;
}else{
checked=false;
}
}else{
checked=false;
}
if(!checked){
//User Doesn't exists
servletResponse.sendRedirect("http://localhost:8080/MySite/pages/Create_Profile.html");
}else{
servletResponse.sendRedirect("http://localhost:8080/MySite/{email}"); <<<< How to redirect using #FormParam("email")
}
}
createprofile
#POST
#Produces(MediaType.TEXT_HTML)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public void newUser(
#FormParam("email") String email,
#FormParam("password") String password,
#Context HttpServletResponse servletResponse
) throws IOException {
User u = new User(email,password);
User.userdata.put(email,password);
}
Your usage of userdata [Map] looks wrong to me. Is it a part of user class, is it non static or static ?
If it is non static then every time you will do new User() .. that map will be initialized and it will have no data in it. Hence u1.userdata.containsKey(emailc); will be always false.
If you are using a hashmap as a temporary database for dev purposes then, make it static rather keep it in a different class like UserStore or some DB access layer. Exmaple below:
public class UserDAO(){
private static Map<String,User> userdata = new HashMap<String,User>();
public boolean hasUser(String email){
return userdata.contains(email);
}
public User saveUser(String email, String password ...){
//make user object save it in map and return the same
}
// more methods for delete and edit etc.
}
And use this in your REST layer classes like this
exists = userDao.hasUser(email);
Advantages :
Your problem will be solved.
Later on when you move to actual db implementation you will just have to change your UserDao code and rest application code will be just fine. -- Loose coupling :)
Also regarding forward using email
servletResponse.sendRedirect("http://localhost:8080/MySite/{email}"); <<<< How to redirect using #FormParam("email")
add the email parameter there in the url only, if thats what you want:
servletResponse.sendRedirect("http://localhost:8080/MySite/"+emailc);
UPDATE :
See the fundamental thing is that you get request parameters [email , password]. You check it whether it is present in map or not. Now what you are doing wrong here is you create a new user like this User u = new User(); and then get email and password from it emailc = u.getEmail();. This emailc will always be null and your userdata map will always return false for that. You have two choices :
Either set email and password in user object and then get the data from user object.
Use the email and password obtained from request parameters for your logic. Do not alter them
One good practice to follow while programming is that at all times think of your method parameters as final parameters.
UPDATE 2 :
if(mypass==pass){
checked=true;
}else{
checked=false;
}
Change == to equals method. String matching should be done by equals or equalsIgnoreCase method not ==.
You always create a new User without any parameters: User u1=new User();. All these User instances will have the same property values and probably exists is always false.
Does anyone know for an example of GWT's CellTable using RequestFactory and that table is being edited? I would like to list objects in a table (each row is one object and each column is one property), be able to easily add new objects and edit. I know for Google's DynaTableRf example, but that one doesn't edit.
I searched Google and stackoverflow but wasn't able to find one. I got a bit confused with RF's context and than people also mentioned some "driver".
To demonstrate where I currently arrived, I attach code for one column:
// Create name column.
Column<PersonProxy, String> nameColumn = new Column<PersonProxy, String>(
new EditTextCell()) {
#Override
public String getValue(PersonProxy person) {
String ret = person.getName();
return ret != null ? ret : "";
}
};
nameColumn.setFieldUpdater(new FieldUpdater<PersonProxy, String>() {
#Override
public void update(int index, PersonProxy object, String value) {
PersonRequest req = FaceOrgFactory.getInstance().requestFactory().personRequest();
PersonProxy eObject = req.edit(object);
eObject.setName(value);
req.persist().using(eObject).fire();
}
});
and my code for data provider:
AsyncDataProvider<PersonProxy> personDataProvider = new AsyncDataProvider<PersonProxy>() {
#Override
protected void onRangeChanged(HasData<PersonProxy> display) {
final Range range = display.getVisibleRange();
fetch(range.getStart());
}
};
personDataProvider.addDataDisplay(personTable);
...
private void fetch(final int start) {
lastFetch = start;
requestFactory.personRequest().getPeople(start, numRows).fire(new Receiver<List<PersonProxy>>() {
#Override
public void onSuccess(List<PersonProxy> response) {
if (lastFetch != start){
return;
}
int responses = response.size();
if (start >= (personTable.getRowCount()-numRows)){
PersonProxy newP = requestFactory.personRequest().create(PersonProxy.class);
response.add(newP);
responses++;
}
personTable.setRowData(start, response);
personPager.setPageStart(start);
}
});
requestFactory.personRequest().countPersons().fire(new Receiver<Integer>() {
#Override
public void onSuccess(Integer response) {
personTable.setRowCount(response+1, true);
}
});
}
I try to insert last object a new empty object. And when user would fill it, I'd insert new one after it. But the code is not working. I says that user is "attempting" to edit a object previously edited by another RequestContext.
Dilemmas:
* am I creating too many context'es?
* how to properly insert new object into celltable, created on the client side?
* on fieldUpdater when I get an editable object - should I insert it back to table or forget about it?
Thanks for any help.
am I creating too many context'es?
Yes.
You should have one context per HTTP request (per fire()), and a context that is not fire()d is useless (only do that if you/the user change your/his mind and don't want to, e.g., save your/his changes).
You actually have only one context to remove here (see below).
Note that your approach of saving on each field change can lead to "race conditions", because a proxy can be edit()ed by at most one context at a time, and it remains attached to a context until the server responds (and once a context is fired, the proxy is frozen –read-only– also until the server responds).
(this is not true in all cases: when onConstraintViolation is called, the context and its proxies are unfrozen so you can "fix" the constraint violations and fire the context again; this should be safe because validation is done on the server-side before any service method is called).
how to properly insert new object into celltable, created on the client side?
Your code looks OK, except that you should create your proxy in the same context as the one you'll use to persist it.
on fieldUpdater when I get an editable object - should I insert it back to table or forget about it?
I'm not 100% certain but I think you should refresh the table (something like setRowData(index, Collections.singletonList(object)))
BTW, the driver people mention is probably the RequestFactoryEditorDriver from the Editor framework. It won't help you here (quite the contrary actually).
I'm trying to bind a plugin to the update contact event in Microsoft Dynamics CRM 2011.
I've made a plugin and i already registered the assembly and step for my organisation.
screenshot: CRM registration tool
For this moment, i'm using sample code for my plugin.
public class Plugin : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
Entity entity;
// Check if the input parameters property bag contains a target
// of the create operation and that target is of type Entity.
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
// Obtain the target business entity from the input parameters.
entity = (Entity)context.InputParameters["Target"];
// Verify that the entity represents a contact.
if (entity.LogicalName != "contact") { return; }
}
else
{
return;
}
try
{
IOrganizationServiceFactory serviceFactory =
(IOrganizationServiceFactory)serviceProvider.GetService(
typeof(IOrganizationServiceFactory));
IOrganizationService service =
serviceFactory.CreateOrganizationService(context.UserId);
var id = (Guid)context.OutputParameters["id"];
AddNoteToContact(service, id);
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException(
"An error occurred in the plug-in.", ex);
}
}
private static void AddNoteToContact(IOrganizationService service, Guid id)
{
using (var crm = new XrmServiceContext(service))
{
var contact = crm.ContactSet.Where(
c => c.ContactId == id).First();
Debug.Write(contact.FirstName);
var note = new Annotation
{
Subject = "Created with plugin",
NoteText = "This Note was created by the example plug-in",
ObjectId = contact.ToEntityReference(),
ObjectTypeCode = contact.LogicalName
};
crm.AddObject(note);
crm.SaveChanges();
}
}
}
But every time i modify a contact form and save it, i get this error:
The given key was not present in the dictionary
I've been looking for answers for a week now. I hope there is someone here who can guide me to the sollution for this problem. I can give every code or information you need. But for now, i can't think of anything more that maybe can help you to see where my error is located. Any help is very much appreciated.
Thanks!
If the plugin is registered as a pre step, OutputParameters will not contain the key "id" and it will throw that error.
M.Medhat is absolutely correct, but let's expand on it a bit more so you understand.
The first thing that you need to know is the difference between InputParameters vrs OutputParameters. A quick read at this MSDN article describing the difference between InputParameters and OutputParameters.
Make sure to note this statement:
If a plug-in is registered for a pre-event, the OutputParameters property bag would not contain a value for the "id" key because the core operation would not yet have occurred.
Hence, this code would break:
var id = (Guid)context.OutputParameters["id"];
Since you've already created an entity (by casting it off of InputParameters) you could delete that line and do something like this:
AddNoteToContact(service, entity.id);
Don't forget about tracing, it's your best friend. It can show information when an exception is thrown. Here's a good link on it: tracing
Here is some code I use to help show all the parameters the plugin receives when registered for a given message and target entity, use it to find out what keys are present.
If you are less inclined to dig through documentation to see what "should" be there, than to just try and see what actually happens, simply put this in your plugin, register the step you intend to use and it will show you exactly what params were provided for that step.
var propertiesList = String.Join("\n",
context.InputParameters.Select((p,i)=>ParamSelector(p,i,"Input")).Union(
context.InputParameters.Select((p,i)=>ParamSelector(p,i,"Output"))));
//send the list to the tracing service.
context.Trace("Listing Inputput and Output Parameters for the plugin.\n" + propertiesList);
// throw an exception to see the trace values pop-up (in a synchronous plugin).
throw new InvalidPluginExecutionException("Check the trace for a listing of parameters.");
supporting delegates for formatting:
private string ParamSelector(KeyValuePair<string, object> p, int index, string inOut)
{
return String.Format("{2} \tKey:'{0}'\tValue:{1}\n{3}", p.Key, p.Value, inOut, EntityToTraceStrings(p.Value as Entity));
}
private string EntityToTraceStrings(Entity entity)
{
return entity == null ? String.Empty : String.Concat(
String.Format("- Entity: {0} Id: {1}\n\t", entity.LogicalName, entity.Id),
String.Join("\n\t", entity.FormattedValues.Select((p, j) => String.Format("Attribute: {0} \t Value: {1}", p.Key, p.Value))));
}
I am trying to perform a very simple task which is "Add the user with role in the database". The roles are already populated in the database and I am simply adding the role to the User roles collection but it keeps throwing the following exception:
The EntityKey property can only be set when the current value of the property is null.
Here is the code in User.cs:
public void AddRole(Role role)
{
if (!Exists(role))
{
role.User = this;
Roles.Add(role);
}
}
And here is the test that fails:
[Test]
public void should_save_user_with_role_successfully()
{
var _role = _roleRepository.GetByName("Student");
_user.AddRole(_role);
_userRepository.Save(_user);
Assert.IsTrue(_user.UserId > 0);
}
The Repository Code:
public bool Save(User user)
{
bool isSaved = false;
using (var db = new EStudyDevDatabaseEntities())
{
db.AddToUsers(user);
isSaved = db.SaveChanges() > 0;
}
return isSaved;
}
Here is the AddRole Method:
public bool Exists(Role role)
{
var assignedRole = (from r in Roles
where r.RoleName.Equals(role.RoleName)
select r).SingleOrDefault();
if (assignedRole != null) return true;
return false;
}
public void AddRole(Role role)
{
if (!Exists(role))
{
role.User = this;
Roles.Add(role);
}
}
And here is the whole exception:
------ Test started: Assembly: EStudy.Repositories.TestSuite.dll ------
TestCase 'EStudy.Repositories.TestSuite.Repositories.when_saving_new_user.should_save_user_with_role_successfully'
failed: System.InvalidOperationException : The EntityKey property can only be set when the current value of the property is null.
at System.Data.Objects.EntityEntry.GetAndValidateChangeMemberInfo(String entityMemberName, Object complexObject, String complexObjectMemberName, StateManagerTypeMetadata& typeMetadata, String& changingMemberName, Object& changingObject)
at System.Data.Objects.EntityEntry.EntityMemberChanging(String entityMemberName, Object complexObject, String complexObjectMemberName)
at System.Data.Objects.EntityEntry.EntityMemberChanging(String entityMemberName)
at System.Data.Objects.ObjectStateEntry.System.Data.Objects.DataClasses.IEntityChangeTracker.EntityMemberChanging(String entityMemberName)
at System.Data.Objects.DataClasses.EntityObject.set_EntityKey(EntityKey value)
at System.Data.Objects.Internal.LightweightEntityWrapper`1.set_EntityKey(EntityKey value)
at System.Data.Objects.ObjectStateManager.AddEntry(IEntityWrapper wrappedObject, EntityKey passedKey, EntitySet entitySet, String argumentName, Boolean isAdded)
at System.Data.Objects.ObjectContext.AddSingleObject(EntitySet entitySet, IEntityWrapper wrappedEntity, String argumentName)
at System.Data.Objects.DataClasses.RelatedEnd.AddEntityToObjectStateManager(IEntityWrapper wrappedEntity, Boolean doAttach)
at System.Data.Objects.DataClasses.RelatedEnd.AddGraphToObjectStateManager(IEntityWrapper wrappedEntity, Boolean relationshipAlreadyExists, Boolean addRelationshipAsUnchanged, Boolean doAttach)
at System.Data.Objects.DataClasses.RelatedEnd.IncludeEntity(IEntityWrapper wrappedEntity, Boolean addRelationshipAsUnchanged, Boolean doAttach)
at System.Data.Objects.DataClasses.EntityCollection`1.Include(Boolean addRelationshipAsUnchanged, Boolean doAttach)
at System.Data.Objects.DataClasses.RelationshipManager.AddRelatedEntitiesToObjectStateManager(Boolean doAttach)
at System.Data.Objects.ObjectContext.AddObject(String entitySetName, Object entity)
C:\Projects\EStudy\EStudySolution\EStudy.BusinessObjects\Entities\EStudyModel.Designer.cs(97,0): at EStudy.BusinessObjects.Entities.EStudyDevDatabaseEntities.AddToUsers(User user)
C:\Projects\EStudy\EStudySolution\EStudy.BusinessObjects\Repositories\UserRepository.cs(17,0): at EStudy.BusinessObjects.Repositories.UserRepository.Save(User user)
C:\Projects\EStudy\EStudySolution\EStudy.Repositories.TestSuite\Repositories\Test_UserRepository.cs(47,0): at EStudy.Repositories.TestSuite.Repositories.when_saving_new_user.should_save_user_with_role_successfully()
0 passed, 1 failed, 0 skipped, took 6.07 seconds (NUnit 2.5).
UPDATE:
Here is my UserRepository and RoleRepository and they both uses separate contexts:
public bool Save(User user)
{
bool isSaved = false;
using (var db = new EStudyDevDatabaseEntities())
{
db.AddToUsers(user);
isSaved = db.SaveChanges() > 0;
}
return isSaved;
}
public Role GetByName(string roleName)
{
using (var db = new EStudyDevDatabaseEntities())
{
return db.Roles.SingleOrDefault(x => x.RoleName.ToLower().Equals(roleName.ToLower()));
}
}
As, you can see the user and the role are using different context which you have already pointed out. The problem with using single datacontext is that I cannot layer the application properly.
Updated again based on updated question
I disagree that you "can't layer the application properly" when you share a context between repositories. It's a problem that you need to solve, but it's most certainly solvable. Also, I think you will find it considerably easier to solve than the number of problems which you create when you attempt to use multiple contexts.
At any rate, there are really only two possible solutions to your problem:
Manually keep track of which context a particular entity is attached to, and transfer it (with Attach and Detach), when necessary.
Share a Context between repository instances.
In our ASP.NET MVC applications, the logical unit of work is a single Request. Therefore, we instantiate an ObjectContext at the beginning of a request, Dispose it at the end of a request, and inject it into new repositories when we create them. Repository instances never outlast a single request.
Update based on updated question
Does the role repository and the user repository each have a (separate) context? Here's what's going on in the stack trace:
You add the User to the context.
The RelationshipManager goes through the User and ensures that any related entities are also in the context. This involves, among other things, setting their EntityKey property.
Presuming that the Role came from a different context (which appears to be the case, since otherwise the context should detect that the role is already in the context), you should see an error indicating that you cannot add an entity attached to one context into another context. For some reason, you're not seeing that here. But nevertheless, it's not a valid operation.
Instead, you get an error when the EntityKey of the role is assigned.
In my opinion, using a single ObjectContext at a time should be the general rule for working with the EntityFramework. You should use multiple contexts only when you're absolutely forced to, which, in my experience, is almost never. Working with multiple ObjectContexts concurrently is significantly harder than working with one at a time.
OK, I don't know the details of your mapping, but I would expect AddRole to be something more along the lines of:
public void AddRole(Role role)
{
this.Roles.Add(role);
}
... if User->Role is .. or:
public void AddRole(Role role)
{
this.Role = role;
}
if User -> Role is *..1.
If this doesn't help, please post the stack trace for the exception.