update List of users in web services - java

I am trying to update a TextArea with a userList whenever a client enters as an admin. However the first client has only his name and the second has his name with the first client. What I want is to be able to update the list for the first client. For example, if a third client joined in, it should update the list for the first and second clients.
Here is my webservice method
public String getuserList ()
{
String usname = "";
synchronized(username)
{
for (int i = 0; i < username.size(); i++)
{
usname = usname + "\n" + username.get(i);
}
return usname;
}
}
any suggestions?
Thanks.

From an API design standpoint, I would expect a getUserList to return a List than a String. For all other purposes, your implementation looks just OK.
You may consider using StringBuilder to build the final string than the + operator.
EDIT : to show an example scenario.
StringBuilder sb = new StringBuilder();
for (String s : username)
{
sb.append(s);
sb.append("\n");
}
return sb.toString();

Related

How would you make a !!say command for a discord bot?

This is how my commands are set up:
public void onMessageReceived(MessageReceivedEvent evt) {
//Objects
User objUser = evt.getAuthor();
MessageChannel objMsgCh = evt.getChannel();
Message objMsg = evt.getMessage();
//Commands
if(objMsg.getContentRaw().equalsIgnoreCase(Ref.prefix+"say " + message))
{
StringBuilder message = new StringBuilder();
for(int i = 1; i < command.length; i++) {
if(i == command.length-1) {
message.append(command[i]);
}else {
message.append(command[i] + " ");
}
}
objMsgCh.sendMessage(message.toString()).queue();
objMsg.delete();
return;
}
}
It doesn't reply with anything and I don't understand why.
I am using JDA (Java Discord API).
Respect for your creativity but I think you are missing some basic java knowledge. Here is what I think you are aiming for:
public void onMessageReceived(MessageReceivedEvent event){
if(event.getMessage().getContentRaw().startsWith("!!say")){
event.getChannel().sendMessage(event.getMessage().getContentRaw().substring(6)).queue();
event.getMessage().delete().queue();
}
}
I think the if condition is logical. Get the Messages as String in raw format and looking for the string starting with "!!say". Then send a new Message to the channel where the message was received where the message is the raw message as the string with the first five characters (the "!!say") are cut off. So the Bot is repeating the whole message beside the command tag.
Hope this brings you forward in your mission.
I worked out how to do it.
public void onMessageReceived(MessageReceivedEvent evt) {
//Objects
User objUser = evt.getAuthor();
MessageChannel objMsgCh = evt.getChannel();
Message objMsg = evt.getMessage();
if(objMsg.getContentRaw().startsWith(Ref.prefix+"say"))
{
String words = objMsg.getContentRaw().substring(Ref.prefix.length() + 4);
String more_words = words;
objMsgCh.sendMessage(more_words).queue();
You don't really need String more_words = words;
And I do (Ref.prefix.length() + 4) so it says everything after !!say but make sure to make it create something like String prefix = "!!"; because my may not be able to it with the prefix in the if statement. The + 4 counts every just after the prefix and the space between user input.
For Example:
if(objMsg.getContentRaw().startsWith(Ref.prefix+"urban")) {
String query = objMsg.getContentRaw().substring(Ref.prefix.length() + 6);
Because "urban" has 5 characters you would put 6 to account for the space.
Hope that helps.
If you plan on using the JDA-Utilities the following code will work for creating a command.
public class sayCommand extends Command {
public sayCommand() {
this.help = "!say <message>";
this.aliases = new String[] {"!s"};
this.name = "say";
}
#Override
protected void execute(CommandEvent event) {
event.getChannel().sendMessage(event.getMessage().getContentDisplay().split("\\s+", 2)[1]).queue();
}
}
With only using one line, you could have the bot easily mimic your argument.

Java string array doesn't print correctly

I am currently working on a Java program that crawls a webpage and prints out some information from it.
There is one part that I can't figure out, and thats when I try to print out one specific String Array with some information in it, all it gives me is " ] " for that line. However, a few lines before, I also try printing out another String array in the exact same way and it prints out fine. When I test what is actually being passed to the "categories" variable, its the correct information and can be printed out there.
public class Crawler {
private Document htmlDocument;
String [] keywords, categories;
public void printData(String urlToCrawl)
{
nextURL=urlToCrawl;
crawl();
//This does what its supposed to do. (Print Statement 1)
System.out.print("Keywords: ");
for (String i :keywords) {System.out.print(i+", ");}
//This doesnt. (Print Statement 2)
System.out.print("Categories: ");
for (String b :categories) {System.out.print(b+", ");}
}
public void crawl()
{
//Gather Data
//open up JSOUP for HTTP parsing.
Connection connection = Jsoup.connect(nextURL).userAgent(USER_AGENT);
Document htmlDocument = connection.get();
this.htmlDocument=htmlDocument;
System.out.println("Recieved Webpage "+ nextURL);
int guacCounter = 0;
for(Element guac : htmlDocument.select("script"))
{
if(guacCounter==5)
{
//String concentratedGuac = guac.toString();
String[] items = guac.toString().split("\\n");
categories = processGuac(items);
break;
}
else if(guacCounter<5) {
guacCounter++;
}
}
}
public String[] processKeywords(String totalKeywords)
{
String [] separatedKeywords = totalKeywords.split(",");
//System.out.println(separatedKeywords.toString());
return separatedKeywords;
}
public String[] processGuac(String[] inputGuac)
{
int categoryIsOnLine = 6;
String categoryData = inputGuac[categoryIsOnLine-1];
categoryData = categoryData.replace(",","");
categoryData = categoryData.replace("'","");
categoryData = categoryData.replace("|",",");
categoryData = categoryData.split(":")[1];
//this prints out the list of categories in string form.(Print Statement 3)
System.out.println("Testing here: " + categoryData.toString());
String [] categoryList=categoryData.split(",");
//This prints out the list of categories in array form correctly.(Print statement 4)
System.out.println("Testing here too: " );
for(String a : categoryList) {System.out.println(a);}
return categoryList;
}
}
I cut out a lot of the irrelevant parts of my code so there might be some missing variables.
Here is what my printouts look like:
PS1:
Keywords: What makes a good friend, making friends, signs of a good friend, supporting friends, conflict management,
PS2:
]
PS3:
Testing here: wellbeing,friends-and-family,friendships
PS4:
Testing here too:
wellbeing
friends-and-family
friendships

GAE Query with Collection Parameter

I have verified that the entity I am looking for is in the datastore. I have verified that the list I pass as a method parameter contains this entity. I am trying to find all objects that have their 'userGmail' contained in the list of strings I pass.
Here is my code
#SuppressWarnings("unchecked")
#ApiMethod(name = "findFriendsByEmailList")
public CollectionResponse<ZeppaUser> findFriendsByEmailList(
#Named("emailsList") List<String> emailsList, User user)
throws OAuthRequestException {
if (user == null) {
throw new OAuthRequestException(
"Null User Authorization Exception, findFriendsByEmailList");
}
PersistenceManager mgr = null;
List<ZeppaUser> execute = null;
Query query = null;
try {
mgr = getPersistenceManager();
query = mgr.newQuery(ZeppaUser.class);
query.declareParameters("java.util.List emailListParam");
query.setFilter("emailListParam.contains( userGmail )");
execute = (List<ZeppaUser>) query.execute(emailsList);
query.closeAll();
} finally {
mgr.close();
}
return CollectionResponse.<ZeppaUser> builder().setItems(execute)
.build();
}
This is the stack trace I receive from it:
Something worth noting: I do not receive this error on lists I pass in that to not contain an element found in the datastore. Just when it does exist which leads me to believe that the Query has located the element but has not been closed or executed into a return parameter correctly. If it is preferable to return List that is more than ok. I have tried multiple variations of this with no success thus far. It is getting quite frustrating.
Ok so I found a way around it.
Lists cannot be passed into ApiEndpoints. That or I didn't figure out the correct way to do it and would LOVE an update on the proper way to do this.
Instead, in my client, I construct a String of emails seperated by a comma and send a string into the parameter as an 'encoded' string list then 'decode' it upon execution. Works well but seems hacky.
here are the methods I used. This is convenient though because it works with iOS as well.
public static String encodeListString(ArrayList<String> stringList){
StringBuilder stringbuilder = new StringBuilder();
stringbuilder.append(stringList.get(0));
if(stringList.size() > 1){
for( int i = 0; i < stringList.size(); i++){
stringbuilder.append(",");
stringbuilder.append(stringList.get(i));
}
}
return stringbuilder.toString();
}
public static List<String> decodeListString(String encodedString){
char[] characters = encodedString.toCharArray();
StringBuilder stringbuilder = new StringBuilder();
int position = 0;
ArrayList<String> stringList = new ArrayList<String>();
while(true){
try {
char character = characters[position];
if(character == ','){
String resultString = stringbuilder.toString();
stringList.add(resultString);
stringbuilder = new StringBuilder(); // clear it
} else {
stringbuilder.append(character);
}
position++;
} catch (ArrayIndexOutOfBoundsException aiex){
// List ended
String resultString = stringbuilder.toString();
if(!resultString.isEmpty())
stringList.add(resultString);
break;
}
}
return stringList;
}

JAVA - How to access variables inside a FOR loop, from outside the for loop

My code is to add RSS feeds to a list - and the code originally was only to pull one feed from the first position in a list, and add this object to another list.
This was the original code:
public static List<Feed> getFeedsFromXml(String xml) {
Pattern feedPattern = Pattern.compile("<feed>\\s*<name>\\s*([^<]*)</name>\\s*<uri>\\s*([^<]*)</uri>\\s*</feed>");
Matcher feedMatch = feedPattern.matcher(xml);
while (feedMatch.find()) {
String feedName = feedMatch.group(1);
String feedURI = feedMatch.group(2);
feeds.add(new Feed(feedName, feedURI));
}
return feeds;
}
#POST
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.APPLICATION_XML)
public String addXmlFeed() throws IOException
{
int i = 0;
String stringXml = "<feed><name>SMH Top Headlines</name><uri>http://feeds.smh.com.au/rssheadlines/top.xml</uri></feed><feed><name>UTS Library News</name>";
getFeedsFromXml(stringXml);
Feed f = (Feed) feeds.get(0);
feedList.add(f);
String handler = "You have successfully added: \n";
String xmlStringReply = "" + f + "\n";
feedList.save(feedFile);
return handler + xmlStringReply;
}
Everything was going well, and then I decided to implement a for loop for handling the adding of more than one feed to the list, and I tried the following (only the code for the second method in question):
#POST
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.APPLICATION_XML)
public String addXmlFeed() throws IOException
{
int i = 0;
String stringXml = "<feed><name>SMH Top Headlines</name><uri>http://feeds.smh.com.au/rssheadlines/top.xml</uri></feed><feed><name>UTS Library News</name>";
getFeedsFromXml(stringXml);
for (Feed feed: feeds)
{
Feed f = (Feed) feeds.get(i++);
feedList.add(f);
String handler = "You have successfully added: \n";
String xmlStringReply = "" + f + "\n";
}
feedList.save(feedFile);
return handler + xmlStringReply;
}
Now I'm sure this is a basic problem, but now in the line:
return handler + xmlStringReply;
handler and xmlStringReply cannot be resolved to a variable as they are within the FOR LOOP.
Is there any easy way around this?
The scope of those 2 variables is limited to the for loop. To access them outside the loop, you need to increase their scope by declaring them before the loop:
String handler = "";
String xmlStringReply = "";
for (Feed f: feeds) {
feedList.add(f);
handler = "You have successfully added: \n";
xmlStringReply = "" + f + "\n";
}
feedList.save(feedFile);
return handler + xmlStringReply;
Also, your current code overwrites the value of your strings at each loop, whereas you probably meant to concatenate the values. In that case, you could use a StringBuilder instead of string concatenation:
StringBuilder xmlStringReply = new StringBuilder("You have successfully added: \n");
for (Feed f: feeds) {
feedList.add(f);
xmlStringReply.append(f + "\n");
}
feedList.save(feedFile);
return xmlStringReply.toString();
The question you need to answer is "what do I want to return if I add several feeds ?".
Maybe you'd like to return "You have successfully added : feed1 feed2 feed3\n"
In that case, the code is :
StringBuilder response = new StringBuilder( "You have successfully added: ");
for (Feed feed: feeds)
{
feedList.add(feed);
response.append(f.toString()).append(" ");
}
feedList.save(feedFile);
return response.toString();
By the way, your feedand fvariables are just the same and redondant !
Don't write :
int i = 0;
for (Feed feed: feeds)
{
Feed f = (Feed) feeds.get(i++);
feedList.add(f);
}
but
for (Feed feed: feeds)
{
feedList.add(feed);
}
You need to accumulate the result into a variable. I am using StringBuilder because it makes string concatenation efficient.
#POST
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.APPLICATION_XML)
public String addXmlFeed() throws IOException
{
String stringXml = "<feed><name>SMH Top Headlines</name><uri>http://feeds.smh.com.au/rssheadlines/top.xml</uri></feed><feed><name>UTS Library News</name>";
getFeedsFromXml(stringXml);
StringBuilder replyBuilder = new StringBuilder("You have successfully added: \n");
for (Feed feed : feeds)
{
feedList.add(feed);
String xmlStringReply = feed + "\n";
reployBuilder.append(xmlStringReply);
}
feedList.save(feedFile);
return replyBuilder.toString();
}
Because, now they became out of scope.
Beside the original error -- you can easily fix that using other suggestions, I would like to suggest that you should not make feeds as instance variable. I can see your method getFeedsFromXml() is returning the list. So, I think it would have been better if you define that variable inside that method. And then, call the method like,
List<Feed> feeds = getFeedsFromXml(stringXml);
Or in case, this doesn't give you the desired behaviour, then you should rename the method to something, loadFeedsFromXml(). Making that as instance variable may result in threading issues.
Now, trying to improve on your looping,
StringBuilder xmlStringReply = new StringBuilder("You have successfully added: \n");
for (Feed feed: feeds) {
feedList.add(feed);
xmlStringReply.append(f + "\n");
}
feedList.save(feedFile);
return xmlStringReply.toString();
Moreover, I found that your feedList is also a instance variable. And this again can cause threading issues, as it doesn't sound immutable or stateless. Synchronising the methods will give you performance issues. See if you can make it local to this method. A rule of thumb is to keep variable scope as narrow as possible.
A good rule of thumb is to view scope like this:
{ //This is a constructor
int i;
} // This is a deconstructor
anything that is created / instantiated between the curlies only lives inside the curlies. Whenever your working with variables and loops:
for(int i = 0; i < 10; i++){
//some code here
} // after this curly i is no longer in scope or accessible.

Use JDT to get full method name

I am new to eclipse plugin development and I am trying to convert a IMethod to a string representation of the full method name. I.E.
my.full.package.ClassName.methodName(int param, String string)
so far I have had to hand roll my own solution. Is there a better way?
private static String getMethodFullName(IMethod iMethod)
{
String packageString = "[Default Package]";
try {
IPackageDeclaration[] declarations = iMethod.getCompilationUnit().getPackageDeclarations();
if(declarations.length > 0)
{
packageString = declarations[0].getElementName();
}
} catch (JavaModelException e) {
}
String classString = iMethod.getCompilationUnit().getElementName();
classString = classString.replaceAll(".java", "");
String methodString = iMethod.getElementName() + "(";
for (String type : iMethod.getParameterTypes()) {
methodString += type + ",";
}
methodString += ")";
return packageString + "." + classString + "." + methodString;
}
You can get the Fully qualified name for the type using
method.getDeclaringType().getFullyQualifiedName();
This is probably easier than accessing the package from the compilation unit. The rest of you function looks correct.
One small point: you should use StringBuilder to build up the string instead of adding to a standard String. Strings are immutable so addition creates loads of unrecesary temparary objects.
private static String getMethodFullName(IMethod iMethod)
{
StringBuilder name = new StringBuilder();
name.append(iMethod.getDeclaringType().getFullyQualifiedName());
name.append(".");
name.append(iMethod.getElementName());
name.append("(");
String comma = "";
for (String type : iMethod.getParameterTypes()) {
name.append(comma);
comma = ", ";
name.append(type);
}
name.append(")");
return name.toString();
}
Thanks to iain and some more research I have come up with this solution. It seems like something like this should be built into the JDT....
import org.eclipse.jdt.core.Signature;
private static String getMethodFullName(IMethod iMethod)
{
StringBuilder name = new StringBuilder();
name.append(iMethod.getDeclaringType().getFullyQualifiedName());
name.append(".");
name.append(iMethod.getElementName());
name.append("(");
String comma = "";
String[] parameterTypes = iMethod.getParameterTypes();
try {
String[] parameterNames = iMethod.getParameterNames();
for (int i=0; i<iMethod.getParameterTypes().length; ++i) {
name.append(comma);
name.append(Signature.toString(parameterTypes[i]));
name.append(" ");
name.append(parameterNames[i]);
comma = ", ";
}
} catch (JavaModelException e) {
}
name.append(")");
return name.toString();
}
I am not sure it would take into account all cases (method within an internal class, an anonymous class, with generic parameters...)
When it comes to methods signatures, the classes to look into are:
org.eclipse.jdt.internal.corext.codemanipulation.AddUnimplementedMethodsOperation
org.eclipse.jdt.internal.corext.codemanipulation.StubUtility2
You need to get the jdt.core.dom.IMethodBinding, from which you can extract all what you need.
If you have a MethodInvocation, you can:
//MethodInvocation node
ITypeBinding type = node.getExpression().resolveTypeBinding();
IMethodBinding method=node.resolveMethodBinding();

Categories