connection to a red5 remote shared object from a flex app - java

I'm writing a Flex application.
The server side application is Java application that is on top of Red5 1.0.
that connection is made throught RTMPE protcol. (the results are the same with RTMP or RTMPE).
I have am able to properly connect to the server and enter and leave rooms, but I am not able to connect to a shared object in a room. using a non-persistent shared object.
I create a shared object in a room in the server side using the following code:
private void createSharedObject (IScope scope, String soName, boolean persistent) {
ISharedObjectService service= (ISharedObjectService) ScopeUtils
.getScopeService(scope,
ISharedObjectService.class,
false);
service.createSharedObject(scope, soName, persistent);
}
private ISharedObject getSharedObject(IScope scope, String soName,boolean persistent) {
ISharedObjectService service = (ISharedObjectService) ScopeUtils
.getScopeService(scope,
ISharedObjectService.class,
false);
return service.getSharedObject(scope, soName,persistent);
}
public ISharedObject getRoomSharedObject() {
final String soName = "room_" + this._scope.getName();
log.debug("application found. creating shared object");
log.debug("shared object: {} not found for scope: {}. creating one",new Object[]{soName,this._scope.getContextPath()});
createSharedObject(this._scope, soName, XpoConstants.persistentSharedObjects);
ISharedObject so = getSharedObject(this._scope,soName, XpoConstants.persistentSharedObjects);
so.clear();
return so;
}
then the user enters the proper room I get the connction, and invoke a function at his end and provide the Shared Object name so he will know what to to connect to using the following code:
IConnection conn = Red5.getConnectionLocal();
IServiceCapableConnection sc = (IServiceCapableConnection) conn;
sc.invoke("<function name>", new Object[]{this._so.getName(),...});
now in the client side,
I use the following code in the flex application to get the remote shared object:
var roomSharedObject:SharedObject = SharedObject.getRemote(soName, SharedUtils.getNetConnection().uri, Finals.persistentSharedObject);
roomSharedObject.addEventListener(NetStatusEvent.NET_STATUS, this._parse);
roomSharedObject.addEventListener(SyncEvent.SYNC,this._parse2);
roomSharedObject.connect(SharedUtils.getNetConnection());
...
private function _parse(e:NetStatusEvent):void {
trace("NETSTATUSEVENT");
trace("########## EVENT INFO CODE: " + e.info.code);
}
private function _parse2(e:SyncEvent):void {
trace("SYNCEVENT");
}
the only message that I get from red5 is the following:
[INFO] [pool-8-thread-12] org.red5.server.so.SharedObject - Deleting shared object room_3963 because all clients disconnected and it is no longer acquired.
I would guess that NetStatusEvent should be triggered would some kind of error message
but I get no trace messages at all! and the only thing that I get from red5 is that the shared object is deleted which means that that client tried to connect for a sec and disconnected.
I tired to google, tired the red5 google group. i'm lost!
any information regarding the issue would be greatly appreciated.
thank you!
update
ok I created a smaller client and server..
at the server, the appConnect function just return true.
the client is a flex 4.6 client with the following code:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" creationComplete="init()"
minHeight="600">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
private var nc:NetConnection = new NetConnection();
private function init():void {
nc.proxyType = "best";
nc.objectEncoding = ObjectEncoding.AMF0;
nc.addEventListener (NetStatusEvent.NET_STATUS,checkConnect);
nc.connect("rtmpe://127.0.0.1/ufktest");
}
private function checkConnect (event:NetStatusEvent):void
{
switch (event.info['code']) {
case 'NetConnection.Connect.Success':
{
_red5Connected();
trace('connected succesfully');
break;
}
case 'NetConnection.Connect.Closed':
{
_red5Disconnected();
trace('connection closed');
break;
}
case 'NetConnection.Connect.Rejected':
{
_red5Disconnected();
trace('connection rejected' );
break;
}
case 'NetConnection.Connect.Failed':
{
_red5Disconnected();
trace('connection failed');
break;
}
case 'NetConnection.Connect.AppShutDown':
{
trace('app shut down');
_red5Disconnected();
break;
}
default:
{
trace("unknown netconenction status: " + event.info['code']);
break;
}
}
}
private function _red5Connected():void {
trace("red5 connection was successful");
var roomSharedObject:SharedObject = SharedObject.getRemote("moshe",nc.uri,false);
roomSharedObject.addEventListener(NetStatusEvent.NET_STATUS, _parse);
roomSharedObject.addEventListener(SyncEvent.SYNC,_parse2);
roomSharedObject.connect(nc);
}
private function _parse(e:NetStatusEvent):void {
trace("NETSTATUSEVENT");
trace("########## EVENT INFO CODE: " + e.info.code);
}
private function _parse2(e:SyncEvent):void {
trace("SYNCEVENT");
}
private static function _red5Disconnected():void {
trace("disconnected from red5");
Alert.show("could not connect to server, please try again later");
}
]]>
</fx:Script>
and still when I run the client application it connects to the server and give me the following error:
[INFO] [pool-8-thread-15] org.red5.server.so.SharedObject - Deleting shared object moshe because all clients disconnected and it is no longer acquired.

Any more logs? However your log suggests that the shared object was created successfully on the server.Try using acquire() method on creation of the shared object inside roomStart() or wherever you are creating it(roomStart() should be the right place though). Server by default would destroy any shared object if no client is connected.

This seems like an overly complex way to do this. If you use the Flex method SharedObject::getRemote all of this will be taken care of for you. If the object exists the client will get a copy. If it doesn't exist the object will be created. So first person in 'the room' creates the object and anyone that shows up later will get a copy.

Related

how to create a connection pool/only once for a third party Application?

I'm using JAVA/Spring MVC and I need to make a Connection Pool for a Third Party Application integration in my application becouse when i try to connect it multiple time my application and server System utilize 100% RAM.
here i have to problem, when users start to hit a specific method (callGenerationService()) multiple time, my Heap memory(RAM space) increases and becomes 100% and application going to slow becouse of it connect third party application multiple times ? here i need to create a connection only once and get it multiple times. where my connection like,
public class ClickToCallServiceImpl implements ClickToCallServiceInterface {
Client client = null;
#Override
public ClickToCall callGenerationService(ClickToCall clickToCall) {
client = new Client();
client.connect("127.0.0.1", 8021 , "password", 10); //Every time Connection Connect.
client.setEventSubscriptions("plain", "all");
// client.sendSyncApiCommand("",""); //here i run command on every hit like.
client.sendSyncApiCommand(clickToCall.command1, clickToCall.command2);
client.close();
}
}
and here 'ClickToCall' is a #Component Bean/POJO Class with variables setters and getters.
Is there, how to we create a connection (either pool or only once connect) for above connection where i connect only once and hit clickToCall.Command1 and clickToCall.Command2 multiple times and utilize less RAM? Thanks in advance.
Please note that I'm not an expert of freeswitch esl so you must check the code properly. Anyway this is what I would do.
First I create a Factory for Client
public class FreeSwitchEslClientFactory extends BasePooledObjectFactory<Client> {
#Override
public Client create() throws Exception {
//Create and connect: NOTE I'M NOT AN EXPERT OF ESL FREESWITCH SO YOU MUST CHECK IT PROPERLY
Client client = new Client();
client.connect("127.0.0.1", 8021 , "password", 10);
client.setEventSubscriptions("plain", "all");
return client;
}
#Override
public PooledObject<Client> wrap(Client obj) {
return new DefaultPooledObject<Client>(obj);
}
}
Then I create a shareable GenericObjectPool:
#Configuration
#ComponentScan(basePackages= {"it.olgna.spring.pool"})
public class CommonPoolConfig {
#Bean("clientPool")
public GenericObjectPool<Client> clientPool(){
GenericObjectPool<Client> result = new GenericObjectPool<Client>(new FreeSwitchEslClientFactory());
//Pool config e.g. max pool dimension
result.setMaxTotal(20);
return result;
}
}
Finally I use the created pool in order to get the Client obj:
#Component
public class FreeSwitchEslCommandSender {
#Autowired
#Qualifier("clientPool")
private GenericObjectPool<Client> pool;
public void sendCommand(String command, String param) throws Exception{
Client client = null;
try {
client = pool.borrowObject();
client.sendSyncApiCommand(command, param);
} finally {
if( client != null ) {
client.close();
}
pool.returnObject(client);
}
}
}
I didn't test (also because I can't) it but it should work. In any case I pray you to properly check the configuration. I don't know if it's OK to always create a Client object and connect or if it's better to connect when you want to send command
I hope it can be useful
EDIT INFORMATION
Sorry I made an error early. You must return the client to the pool
I updated my FreeSwitchEslCommandSender class
Angelo

How to set various parameters for Java RMI based communication?

While performing a client-server communication with various forums, I am unable to perform Remote-object's lookup on the client machine.
The errors which I receive are ConnectIOException(NoRouteToHostException), and sometimes ConnectException and sometimes someother.
This is not what I want to ask. But, the main concern is how should I setup client platform and server platform --- talking about networking details --- this is what I doubt interferes with my connection.
My questions :-
How should I edit my /etc/hosts file on both client-side and server-side? Server's IP- 192.168.1.8 & Client's IP-192.168.1.100. Means, should I add the system name in both the files:
192.168.1.8 SERVER-1 # on the server side
192.168.1.100 CLIENT-1 # on the client side
Should I edit like this? Can this be one of the possible concerns? I just want to remove any doubts left over to perform the rmi-communication!
Also, I am also setting Server's hostname property using System.setProperty("java.rmi.server.hostname",192.168.1.8); on the server side. Should I do the same on the client-side too?
I've read about setting classpath while running the java program on both server-side as well as the client-side. I did this too,but,again the same exceptions. No difference at all. I've read that since Java update 6u45, classpaths aren't necessary to include! Please throw some light on this too...
If I am missing something, Please enlighten about the same too. A brief idea/link to resources are most preferred.
You don't need any of this unless you have a problem. The most usual problem is the one described in the RMI FAQ #A.1, and editing the hosts file of the server or setting java.rmi.server.hostname in the server JVM is the solution to that.
'No route to host' is a network connectivity problem, not an RMI problem, and not one you'll solve with code or system property settings.
Setting the classpath has nothing to do with network problems.
Here is server example of which transfers an concrete class. This class must be exist in server and client classpath with same structure
Message:
public class MyMessage implements Serializable {
private static final long serialVersionUID = -696658756914311143L;
public String Title;
public String Body;
public MyMessage(String strTitle) {
Title = strTitle;
Body = "";
}
public MyMessage() {
Title = "";
Body = "";
}
}
And here is the server code that gets an message and returns another message:
public class SimpleServer {
public String ServerName;
ServerRemoteObject mRemoteObject;
public SimpleServer(String pServerName) {
ServerName = pServerName;
}
public void bindYourself() {
try {
mRemoteObject = new ServerRemoteObject(this);
java.rmi.registry.Registry iRegistry = LocateRegistry.getRegistry(RegistryContstants.RMIPort);
iRegistry.rebind(RegistryContstants.CMName, mRemoteObject);
} catch (Exception e) {
e.printStackTrace();
mRemoteObject = null;
}
}
public MyMessage handleEvent(MyMessage mMessage) {
MyMessage iMessage = new MyMessage();
iMessage.Body = "Response body";
iMessage.Title = "Response title";
return iMessage;
}
public static void main(String[] server) {
SimpleServer iServer = new SimpleServer("SERVER1");
iServer.bindYourself();
while (true) {
try {
Thread.sleep(10000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
and here is the remote interface of server remote object:
public interface ISimpleServer extends java.rmi.Remote{
public MyMessage doaction(MyMessage message) throws java.rmi.RemoteException;
}
all you need is adding MyMessage class both in server and client classpath.

How to stop streaming in the publish method of Wowza server

I need to stop publishing the stream in the publish() method and send the client a message such as "This name is incorrect, choose another."
I've looked at sendClientOnErrorStatus() but haven't found any examples showing how to handle it on the client side.
Also, can anyone explain what the sendResult(..) method does?
sendClientOnErrorStatus() and sendResult() only work in a Flash context.
sendClientOnErrorStatus()
On the Wowza server you can override the publish and releaseStream (for streams being published) methods and do something like:
sendClientOnStatusError(client, "NetStream.Publish.Denied", "Stream name is invalid: " + streamName);
On a Flash client using ActionScript you would add a NetStatusEvent listener:
nc = new NetConnection();
nc.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
private function netStatusHandler(event:NetStatusEvent):void {
switch (event.info.code) {
// do something with the event.info
}
}
sendResult()
This is used to send the result for a NetConnection.call which calls a custom method on the Wowza server.
Example:
Wowza server:
public void someMethod(IClient client, RequestFunction function,
AMFDataList params) {
{
sendResult(client, params, "response");
}
Client:
nc = new NetConnection();
nc.call("someMethod",new Responder(function(data:String):void {
trace(data);
})
);
Source: AS3 Reference

Gemfire - IllegalStateException on cache create

I'm trying to run a Gemfire client app but I'm getting an IllegalStateException when running the following code:
//clientPool is the name of the pool from the client
DynamicRegionFactory.Config config = new DynamicRegionFactory.Config(null,(String)"clientPool",false,true);
dynRegFact = DynamicRegionFactory.get();
dynRegFact.open(config);
_cache = new ClientCacheFactory().set("locators", "")
.set("mcast-port", "0").set("log-level", "error")
.set("cache-xml-file", xmlFileName)
.create();
Exception in thread "main" java.lang.IllegalStateException: The client pool of a DynamicRegionFactory must be configured with queue-enabled set to true.
I can't figure out how to set the queue-enabled to true. I would appreciate some code, not answers like "check this part of the documentation". I've already looked everywhere.
You should enable subscription in your pool. Just add subscription-enabled="true" attribute to your pool configuration.
Note: Your client should support transactions. It's better to use dynamic regions on cache servers. From client call remote function.
Example:
Function:
public class CreateRegionFunction extends FunctionAdapter {
#Override
public void execute(FunctionContext fc) {
String name = (String) fc.getArguments();
Region reg = DynamicRegionFactory.get().createDynamicRegion("/parent",
name);
if (reg == null) {
fc.getResultSender().lastResult("ERROR");
} else {
fc.getResultSender().lastResult("DONE");
}
}
#Override
public String getId() {
return "create-region-function";
}
}
Server side:
CreateRegionFunction creatRegFun = new CreateRegionFunction();
FunctionService.registerFunction(creatRegFun);
Add dynamic-region-factory in your server cache:
<dynamic-region-factory />
Client side:
FunctionService.onServer(PoolManager.find("poolName"))
.withArgs("child")
.execute("create-region-function")
.getResult();
In this case it's not obligatory to use DynamicRegionFactory, you can use RegionFactory and create root regions.

BlazeDS StreamingAMF: How to detect when flex client closes the connection?

I have a Flex application that connects to a BlazeDS server using the StreamingAMF channel.
On the server-side the logic is handled by a custom adapter that extends ActionScriptAdapter and implements FlexSessionListener and FlexClientListener interfaces.
I am asking how can I detect which "flex-client" has closed a connection when for example the user is closing the browser? (so I can clean some infos inside the database)
I tried using the following:
1. To manually manage the command messages:
#Override
public Object manage(final CommandMessage commandMessage) {
switch (commandMessage.getOperation()) {
case CommandMessage.SUBSCRIBE_OPERATION:
System.out.println("SUBSCRIBE_OPERATION = " + commandMessage.getHeaders());
break;
case CommandMessage.UNSUBSCRIBE_OPERATION:
System.out.println("UNSUBSCRIBE_OPERATION = " + commandMessage.getHeaders());
break;
}
return super.manage(commandMessage);
}
But the clientID's are always different from the ones that came.
2. Listening for sessionDestroyed and clientDestroyed events
#Override
public void clientCreated(final FlexClient client) {
client.addClientDestroyedListener(this);
System.out.println("clientCreated = " + client.getId());
}
#Override
public void clientDestroyed(final FlexClient client) {
System.out.println("clientDestroyed = " + client.getId());
}
#Override
public void sessionCreated(final FlexSession session) {
System.out.println("sessionCreated = " + session.getId());
session.addSessionDestroyedListener(this);
}
#Override
public void sessionDestroyed(final FlexSession session) {
System.out.println("sessionDestroyed = " + session.getId());
}
But those sessionDestroyed and clientDestroyed methods are never called. :(
I made it the following way, by using a custom adapter and a static class with a list of connected clients.
#Override
public Object manage(final CommandMessage commandMessage) {
switch (commandMessage.getOperation()) {
case CommandMessage.SUBSCRIBE_OPERATION:
// add user info
// be aware - each time the selector changes this method is called. So when you add user info check to see if you are not duplicating the clients.
addInfoAboutUser(commandMessage.getHeader("DSId").toString(), commandMessage.getClientId().toString());
break;
case CommandMessage.UNSUBSCRIBE_OPERATION:
clearUserInfo(commandMessage.getClientId().toString());
break;
}
return null;
}
-
Code INFO:
addInfoAboutUser() and clearUserinfo() are private methods in my class that manage the static list of connected clients.
-
NOTE: when a selector is changed from the flex client side the manage() method will be called twice: 1st to unsubscribe and 2nd to subscribe with the new selector.
You need to catch the event onbeforeunload and call a method on server which will cleanup all the client related data. Otherwise there is no way for the Flex client to automatically detect that it is unloaded.
The session should be destroyed when the maximum inactivity interval is exceeded...if the web.xml is properly configured.
Had the same problem as you ... solved it by a "hack" of BlazeDS ... I documented it on my confluence. Perhaps it helps with your problem:
http://dev.c-ware.de/confluence/display/PUBLIC/Litening+for+BlazeDS+client+logins+and+logouts

Categories

Resources