Cannot call method in red5 server from AS3 Flash CS6 - java

Okay, this had been making me very mad. I've followed almost 8 tutorials all over the Internet and in the end, I got my Red5 server instance working. Good for me! But when I'm calling my Java methods in my Red5 apps from my AS3 apps, in the 'Console' window in Eclipse, I got this error :
[ERROR] [NioProcessor-1] org.red5.server.service.ServiceInvoker - Method getTheName with parameters [] not found in org.red5.core.Application#17e5fde
Here's my Application.java file.
package org.red5.core;
import org.red5.server.adapter.ApplicationAdapter;
import org.red5.server.api.IConnection;
import org.red5.server.api.IScope;
import org.red5.server.api.service.ServiceUtils;
/**
* Sample application that uses the client manager.
*
* #author The Red5 Project (red5#osflash.org)
*/
public class Application extends ApplicationAdapter {
/** {#inheritDoc} */
#Override
public boolean connect(IConnection conn, IScope scope, Object[] params) {
return true;
}
/** {#inheritDoc} */
#Override
public void disconnect(IConnection conn, IScope scope) {
super.disconnect(conn, scope);
}
public String getTheName() { return "MyName!"; }
}
And here's my AS3 code. I just put this on the Timeline.
var nc:NetConnection = new NetConnection();
nc.connect("http://localhost/Mintium/RoomHere", "SomeUsernameHere");
nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
nc.objectEncoding = ObjectEncoding.AMF0;
function onNetStatus(e:NetStatusEvent):void
{
switch (e.info.code)
{
case "NetConnection.Connect.Success" :
trace("connected");
nc.call("getTheName", new Responder(getName_result, getName_error));
break;
}
}
function getName_result(res:Object):void { append("Name : " + res.toString()); }
function getName_error(res:Object):void { append(res.toString()); }
Its been a week I've been trying to figure it out and my dateline is next month. If this stuff is not solved, I'm gonna fail my assessment. Please help me with my problems. Thank you very much.

Sorry I did not see this 2 months ago, I could have helped you pass your assessment. Nevertheless, I think I can answer this question, having had a similar problem calling Red5 services.
The key to solving this problem is in those parts of Red5 that utilize the Spring Framework. In your project, there should be a file called red5-web.xml that resides in the Server project's WEB-INF folder. This file contains some Bean dependencies used by Red5's Spring components. This is not mentioned in the tutorials that I read, or even in most of the (rather sparse and distributed) red5 programming documentation.
What you have to do is add a bean entry for your method in that file. In your case, the entry should look like this:
<bean id="getTheName.service" class="org.red5.core.Application" />
Note my use of the name of your function, with ".service" appended. I do not understand why, but you need the ".service" appended in order for Red5 to find your function. You need to add a similar entry for every class whose functions you want to use as services.
Of course, I based everything I said above on the fact that you put the service into the Application class -- something which I never do. if you read the red5-web.xml file, you will see that there is already an entry for that class, because it is already injected through Spring as the class that acts as an "endpoint" for processing requests over the web. I do not know if using the Application class as an endpoint and a provider of services is a good idea (it violates "separation of concerns" in OOP and may cause problems with Spring).
What I usually do is add a separate class in the org.red5.core package (or any other package you might want) that acts to deliver the desired service, then put an entry into red5-web.xml that injects the class and its method. So, for your project, lets assume you have a class called NameProvider in the org.red5.core package:
public class NameProvider
{
public NameProvider() {}
public String getTheName() { return("MyName!"); }
}
then you add the following entry to your red5-web.xml file:
<bean id="getTheName.service" class="org.red5.core.NameProvider" />
That should make everything work.
I hope this helps you in the future, or anyone else having this problem. I just wish I'd seen this question sooner.

Related

setServletContext not activating inside #Configuration file

So, this is something of a follow-on of this question. My current code looks something like this:
#Configuration
#EnableAutoConfiguration
#ComponentScan(basePackages = {"base.pkg.name"})
public class MyApp implements ServletContextAware {
private ThingDAO beanThingDAO = null;
public MyApp() {
// Lots of stuff goes here.
// no reference to servletContext, though
// beanThing gets initialized, and mostly populated.
}
#Bean publicD ThingDAO getBeanThingDAO() { return beanThingDAO; }
public void setServletContext(ServletContext servletContext) {
// all references to servletContext go here, including the
// bit where we call the appropriate setters in beanThingDAO
{
}
The problem is, it's not working. Specifically, my understanding was that setServletContext was supposed to be called by various forms of Spring Magic at some point during the startup process, but (as revealed by System.out.println()) it never gets called. I'm trying to finish up the first stage of a major bunch of refactoring, and for the moment it is of notable value to me to be able to handle the access to servletContext entirely inside of the #Configuration file. I'm not looking for an answer that will tell me that I should put it in the controllers. I'm looking for an answer that will either tell me how to get it working inside of the #Configuration file, or explain why that won't work, and what I can do about it.
I just ran into a very similar issue and while I'm not positive it's exactly the same problem I thought I'd record my solution in case it's helpful to others.
In my case I had a single #Configuration class for my spring boot application that implemented both ServletContextAware and WebMvcConfigurer.
In the end it turns out that Spring Boot has a bug (or at least undocumented restraint) that ServletContextAware.setServletContext() will never be called if you also implement WebMvcConfigurer on the same class. The solution was simply to split out a separate #Configuration class to implement ServletContextAware.
Here's a simple project I found that demonstrates and explains more what the problem was for me:
https://github.com/dvntucker/boot-issue-sample
The OP doesn't show that the bean in question was implementing both of these, but given the OP is using simplified example code I thought maybe the fact that the asker could have been implementing both interfaces in his actual code and might have omitted the second interface.
Well, I have an answer. It's not one I'm particularly happy with, so I won't be accepting it, but if someone with my same problem stumbles across this question, I want to at least give them the benefit of my experience.
For some reason, the ServletContextAware automatic call simply doesn't work under those circumstances. It works for pretty much every other component, though. I created a kludge class that looks something like this:
// This class's only purpose is to act as a kludge to in some way get
// around the fact that ServletContextAware doesn't seem to work on MyApp.
// none of the *other* spring boot ways of getting the servlet context into a
// file seem to work either.
#Component
public class ServletContextSetter implements ServletContextAware {
private MyApp app;
public ServletContextSetter(MyApp app) {
this.app = app;
}
#Override
public void setServletContext(ServletContext servletContext) {
app.setServletContext(servletContext);
}
}
Does the job. I don't like it, and I will be rebuilding things later to make it unnecessary so I can take it out, but it does work. I'm going to hold the checkmark, though, in case anyone can tell me either how to make it work entirely inside the #Configuration - decorated file, or why it doesn't work there.
Note that the #Component decorator is important, here. Won't work without it.

Spring - Passing Listener via RMI

Basis
I have several projects, which implement a caching service - each its own, and each one is almost the same as the others. I have coompressed and shortened the existing cacheservices into a single project containing two different cache services - one for basic objects, and one for complex objects (which extends the basic service). I have created 2 projects - one to deploy as a .war-file and the API-project for this.
The entire application runs on a JBoss AS 7.1 "Thunder" with the latest JDK 7.
Problem
One class in particular requires to be notified whenever an old cache entry is deleted. For this, I implemented a notification procedure using CleanupListeners.
CleanupListener.java
public interface CleanupListener extends Remote {
public abstract boolean supports(Class<?> clazz) throws RemoteException;
public abstract void notify(Object removedObject) throws RemoteException;
}
necessary implementations in the cache service
public void registerCleanupListener(CleanupListener listener) {
listeners.add(listener);
}
private void fireCleanupEvent(Object removedObject) {
for (CleanupListener cleanupListener : listeners) {
try {
if (cleanupListener.supports(removedObject.getClass())) {
cleanupListener.notify(removedObject);
}
} catch (RemoteException re) {
LOGGER.error("Remote Listener not available", re);
}
}
}
The listeners are managed via a private final HashSet<CleanupListener>
The project which needs to be notified uses this implementation of the interface:
#Component
public class CleanupEventListener extends UnicastRemoteObject implements CleanupListener {
protected CleanupEventListener() throws RemoteException {
super();
}
#Resource
private ClassRequiresNotification notifyMe;
public boolean supports(Class<?> clazz) {
return SupportedObject.class.isAssignableFrom(clazz);
}
public void notify(Object removedObject) {
notifyMe.someMethod((SupportedObject) removedObject);
}
}
and a registration bean:
#Component
public class CleanupEventListenerRegistrator {
#Resource
private CleanupEventListener cleanupEventListener;
#Resource
private BasicCacheService cacheService;
#PostConstruct
public void init() {
cacheService.registerCleanupListener(cleanupEventListener);
}
}
The remote services are exported via SpringBean:
#Bean
public RmiServiceExporter basicCacheServiceExporter(BasicCacheService basicCacheService) {
RmiServiceExporter cacheService = new RmiServiceExporter();
cacheService.setService(basicCacheService);
cacheService.setServiceName(BASIC_CACHE_SERVICE_NAME);
cacheService.setServiceInterface(some.package.BasicCacheService.class);
return cacheService;
}
and registered via XML-Config:
<bean id="basicCacheService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="lookupStubOnStartup" value="false"/>
<property name="serviceUrl" value="basicCacheService" />
<property name="serviceInterface" value="some.package.BasicCacheService" />
<property name="refreshStubOnConnectFailure" value="true"/>
</bean>
Exception
So, whenever I try to call the expected methods, I get one of two Exceptions:
Either I get a NoSuchObjectException (rare) or, much more common a ClassNotFoundException wrapped in an UnmarshalException
What I did
I already consulted the JavaDocs, googled massively and have sifted through several questions here, however to no avail. I found a bit of info that the standard property rmi.codebase is set to true, and this might require some rewriting of code, however we are already using RMI at another place in the projects, and it does work fine there. Adding a SecurityManager breaks the rest of our Application (due to external prerequisites) and calls the NoSuchObjectException.
Answers within StackOverflow so far have yielded "this is a problem with the codebase", "you need to install a securityManager", "the classes have to have the same name and be in the same package" and of course "it's the codebase". I am mentioning this one twice, since it does appear quite often yet not a single mention as to how to deal with a codebase problem accompanies it.
Additional Info
I am not sure if this is important, but here's some more info:
The cacheservice-project is configured in java code, the projects which use the service are configured in XML.
The Listener-Interface is not exported vie Annotations or XML-Beans, since several Posts (including at least one here) hinted that this will export the class, but keep listening only on server-side, which is not what I want.
I have also tried to make the CleanupListeneran abstract class, which in itselt extends UnicastRemoteObject but that did not work out either - in fact, it was worse than what I have now.
I am writing and testing the application in eclipse.
Assembling and publishing to server is done by gradle in the command line.
Question
Does anyone know what the problem here is, and how to actually solve it? It is getting quite aggravating when everything I do is either running into an exception or is "yeah that's a codebase error", since both do not help at all.
Any help would be appreciated.
Actual answer
Okay, this is simultaneously embarrassing and relieving. First of all...
The good news
The Listener-Interface as described above works. It is registered on the server-side, and when called, fires a notification to the client, which then may act accordingly. So, if you have been looking for an answer to the whole "passing a listener"-problem, there you have it.
The bad news
however is that I have been quite ignorant to certain facts. Among other things, what the term codebase actually covers. In my particular case, the problem was that the cacheservice itself had no dependencies on the other projects, which (custom) classes it should preserve. So technically, the codebase actually was the problem - due to lacking dependencies in the build.gradle.
I hope I dodn't waste anyone's time on this, if so, please accept my apologies, and hopefully, this question helps someone else sometime.

How to load / insert initial data into database with Ebean in Play Framework?

I need to some initial data (from csv files) into database. I am using Ebean with Play! Framework. I read the doc. It says using YAML files to store the data and call Ebean.save(). And this is done in a Test.
My questions:
Where should I insert my data? (Test is probably not the ideal place, as this data should be used in production)
Can I write my own code to get my data from existing csv files, instead of using YAML files?
Any suggestions or doc links will be appreciated.
Thanks!
A Play Framework 2.4 solution to loading initial data on application startup, using Ebean:
First, create a class where you want perform the initial data load. According to the docs this has to be in the constructor.
public class InitialData {
public InitialData() {
if (Ebean.find(User.class).findRowCount() == 0) {
InputStream is = this.getClass().getClassLoader().getResourceAsStream("initial-data.yml");
#SuppressWarnings("unchecked")
Map<String, List<Object>> all =
(Map<String, List<Object>>)Yaml.load(is, this.getClass().getClassLoader());
//Yaml.load("initial-data.yml"); //calls Play.application() which isn't available yet
Ebean.save(all.get("users"));
}
}
}
NOTE: I used Yaml's load(InputStream is, ClassLoader classloader) method over its load(String resourceName) method because it does not work. I believe this is because of its use of Play.application(), as this is not available before the application is started. Source Here
Second, According to Play docs, to execute code before startup, use Eager-bindings. This will cause your code in the InitialData constructor to execute.
public class MainModule extends AbstractModule implements AkkaGuiceSupport {
#Override
protected void configure() {
//this is where the magic happens
bind(InitialData.class).asEagerSingleton();
}
}
Make sure to add your MainModule class to the application.conf
# modules
play.modules.enabled += "module.MainModule"
With further search, I found the solution is described here
The code that perform initial insertion needs to be hooked into Play's startup.
Hooking into Play’s startup is as simple as creating a class called Global that implements GlobalSettings in the root package, and overriding the onStart() method. Let’s do that now, by creating the app/Global.java fileHooking into Play’s startup is as simple as creating a class called Global that implements GlobalSettings in the root package, and overriding the onStart() method. Let’s do that now, by creating the app/Global.java file
Note that, it said the class needs to be in the root package.
code example:
import play.*;
import play.libs.*;
import com.avaje.ebean.Ebean;
import models.*;
import java.util.*;
public class Global extends GlobalSettings {
#Override
public void onStart(Application app) {
// Check if the database is empty
if (User.find.findRowCount() == 0) {
Ebean.save((List) Yaml.load("initial-data.yml")); // You can use whatever data source you have here. No need to be in YAML.
}
}
}

Lotus Notes: Java Runs Fine when on an Agent, but fails when on a java lib

I created a Web Service Consumer.
I want to call a method that is named setCredentials so I can pass my authentication information to the service.
I have two entities that import the web service consumer, an agent and a java library, meant to be called from LotusScript.
The strange thing is that on my agent everything works fine. Library compiles OK, but when it is executed from LotusScript and reaches that line
stub.setCredentials("xxxx","ttttt");
Java throws a java.lang.nosuchmethod error. What can I be doing wrong?
Thank you so much in advance for your help.
Update:
Maybe I didn't explain fully. The action occurs fully inside java. This is sort of a test. On LotusScript I am just calling the constructor with the sequence GetClass/CreateObject. The code is inside the constructor (For test sake). And it looks precisely the same, both on my test agent and on java library. Answering your question, Jason, no , setCredentials is part of a certain lotus.domino.types.PortTypeBase Interface. When I consume the .wsdl to create a web service consumer, I can see from the generated .java files that my interface extends portTypeBase and Remote
It is not possible to call a Java Web Service consumer from LotusScript (LS2J). This is detailed in SPR SODY7UDKE8 / APAR LO42772. This also applies to calling a Java agent which in turn calls a Java consumer.
You will need to create a LotusScript consumer to access the web service in LotusScript. However there are known limitations in LotusScript which can prevent some web services from being consumed.
40 character variable/method limit
Extremely large SOAP messages can cause performance/crash issues.
Reserved keywords mismatch in LS/WSDL/SOAP.
That said I created the following sample Provider.
Class wsClass
Function hello ( helloText As String) As String
hello = "Hello " + helloText
End Function
End Class
In the NSF it was stored I set it to only allow authenticated users.
I then created a LS consumer and Java Consumer libraries from the generated WSDL.
After that I created the following sample code.
LotusScript
Use "LsWebServiceConsumer"
Sub Initialize
Dim stub As New Wsclass
Dim answer As String
Call stub.Setcredentials("testuser", "password")
answer = stub.Hello("world")
MsgBox answer
End Sub
JAVA (added consumer library to agent)
import lotus.domino.*;
public class JavaAgent extends AgentBase {
public void NotesMain() {
try {
WsClass stub = new WsClassServiceLocator().getDomino();
stub.setCredentials("testuser", "password");
System.out.println(stub.HELLO("world"));
} catch(Exception e) {
e.printStackTrace();
}
}
}
Both of these worked as expected with their own respective consumer.

Suppress console output of player commands

I'm making a bukkit plugin that allows players to lock chests with a password. To protect the players I would like to keep the password from the prying eyes of even the server operator.
I would like to hide the console text that is printed when a player uses a command. For instance, when a player types, /gamemode 1, the console prints out the command and who used it. Is there any way to stop this? Maybe intercept it and wipe it, or garble it?
So I looked around at those plugins, and they're much more complicated than what I need to do this simple thing, so I thought I would post my solution for anybody who stumbles upon this.
What you want to do is create a filter with the java.util.logging.Filter interface. In that you override the isLoggable() function. For my case, this is my exact object that I made.
import java.util.logging.Filter;
import java.util.logging.LogRecord;
public class CustomFilter implements Filter {
#Override
public boolean isLoggable(LogRecord record) {
if(record.getMessage().contains("issued server command: /login")) {
return false;
}
else {
return true;
}
}
}
Then the only other thing you have to do is add this filter to the server logger. The exact line I used is:
CustomFilter filter = new CustomFilter();
plugin.getServer().getLogger().setFilter(filter);
Where plugin is the instance of the plugin in the main class.
Hope this helps anybody who finds this.
There seems to be a couple plug-ins designed for doing this, but neither one is still maintained.
ConsoleFilter
BlockConsoleMessages
One of them may work for you, or you may be able to find the code in them that does what you want.

Categories