问:
Calling Visual Studio Excel add-ins from Excel 2007
I am very new Visual Studio (just downloaded version 2010 Professional), but I believe this is the right way to do web services in excel.

Have created a Excel 2007 Add-In called TestAPI within Visual Studio containing just one class ThisAddIn, the 2 default StartUp and Shutdown procedures and 2 functions I have written myself, say f1 and f2.

When I start Excel 2007 and check Excel Options i can see it as a COM add in, but how can I see these 2 functions within VBA? Any references to either ThisAddIn or TestAPI or f1 or f2 all fail, yet if I put something into the StartUp functions this will automatically be executed whenever I start Excel, which I do find quite annoying. It seems that COM Add-ins are switched on/off at Excel level whereas I cant seem to find the TestAPI anywhere on my list on References (where I could check or uncheck it as required depending on Excel sheet).

I am probably missing an (or multiple) point(s).

答:
Have you declared F1 and F2 Public? In the class ThisAddin

```<code>Public Shared Function F1(x as Object) as Object
  Return x*2
End Function
</code>```

(I'm not sure if Shared is required in VSTO, I use Addin Express, VSTO is such a pain)

Body:
Have you declared F1 and F2 Public? In the class ThisAddin

Public Shared Function F1(x as Object) as Object
  Return x*2
End Function

(I'm not sure if Shared is required in VSTO, I use Addin Express, VSTO is such a pain)


来源: stackexchange

问:
Ratchet Store Connection of User & Send Message Outside of Server Instance
I have been following along with the tutorials here and got the ratchet server working.

My chat class is the same as the tutorial more or less at the moment, so no point in showing that here yet since my question is more about implementation strategy.

In the question I attached the user was looking how to get the connection object of a specific user.  In the top answer solution keeping track of the resource IDs seems to be the way to do this.

For example when the connection is created there is this code.

```<code>public function onOpen(ConnectionInterface $conn) {
        // Store the new connection to send messages to later
        $this->clients[$conn->resourceId] = $conn;
        echo "New connection! ({$conn->resourceId})\n";
    }
</code>```

This creates a member variable clients to store all the connections and you simply reference it now by ID to send a message.  This clients however is an instance of ConnectionInterface $conn

Then to send a message you simply use the code below entering as the array key the id of the client.  Very simple.

```<code>$client = $this->clients[{{insert client id here}}];
$client->send("Message successfully sent to user.");
</code>```

As we know ratchet runs as a script on the server in an event loop never ending.

I'm running a Symfony project in which outside of the server instance running the ratchet code when a user does a certain action in the system I need it to send a message to a particular client connected to the server.

I'm not sure how to do this since the clients are instances of ConnectionInterface and are created when the users first connect via WebSockets. How do I send a message to a particular client in this way?

Here is a visual of what I'm trying to achieve.

References:

how to get the connection object of a specific user?

答:
The solution I am about to post covers the entire process of communicating from server to the client on the web browser including a way to make the Websocket server run in the background (with and without docker).

Step 1:

Assuming you have ratchet installed via composer, create a folder in your project called bin and name the file "startwebsocketserver.php" (or whatever you want)

Step 2:

Copy the following code into it.

```<code><?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use React\Socket\Server;
use React\EventLoop\Factory;

use WebSocketApp\Websocketserver;
use WebSocketApp\Htmlserver;
use WebSocketApp\Clientevent;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Ratchet\App;

require dirname(__DIR__) . '/vendor/autoload.php';
require_once dirname(__DIR__) . '/bootstrap/bootstrap.php';

$websocketserver = new Websocketserver();

$dispatcher = new EventDispatcher(); //@JA - This is used to maintain communication between the websocket and HTTP Rest API Server
$dispatcher->addListener('websocketserver.updateclient', array($websocketserver, 'updateClient'));

//// 1. Create the event loop
$loop = Factory::create();

//// 2. Create websocket servers
$webSock = new Server($loop);
new IoServer(
    new HttpServer(
        new WsServer( $websocketserver )
    ),
    $webSock
);
$webSock->listen('8080', '0.0.0.0');

$app = new App( 'localhost', 6677, '0.0.0.0',$loop );
$app->route( '/', new Htmlserver(), [ '*' ] );//@JA - Allow any origins for last parameter

$app->run();
</code>```

Note that in my example I am using a bootstrap file to load the database.  If you are not using a database or some other method than ignore that.  For the purposes of this answer I will be assuming Doctrine 2 as the database.

What this code does is creates an HTTP server & a WebSocket server within the same code base and at the same time.  I'm using the $app->route approach since you can add further routing for the HTTP server to organize API Calls to talk to the WebSocket Server from your PHP Web Server.

The $loop variable includes the Websocket server in the application loop along with the HTTPServer.

Step 3:

In your project directory create a folder called websockets.  Inside that create another folder called WebSocketApp.  Inside that create 3 empty files for now.

Clientevent.php
Htmlserver.php
Websocketserver.php

We will go into each of these files 1 by 1 next.  Failure to create these directories in this order will cause composer Autoload PSR-0 to fail to find them.

You can change the names but make sure you edit your composer file accordingly.

Step 4:

In your composer.json file make sure it looks something like this.

```<code>{
    "require": {
        "doctrine/orm": "^2.5",
        "slim/slim": "^3.0",
        "slim/twig-view": "^2.1",
        "components/jquery": "*",
        "components/normalize.css": "*",
        "robloach/component-installer": "*",
        "paragonie/random_compat": "^2.0",
        "twilio/sdk": "^5.5",
        "aws/aws-sdk-php": "^3.22",
        "mailgun/mailgun-php": "^2.1",
        "php-http/curl-client": "^1.7",
        "guzzlehttp/psr7": "^1.3",
        "cboden/ratchet": "^0.3.6"
    },
    "autoload": {
        "psr-4": {
            "app\\":"app",
            "Entity\\":"entities"
        },
        "psr-0": {
            "WebSocketApp":"websockets"
        },
        "files": ["lib/utilities.php","lib/security.php"]
    }
}
</code>```

In my case I'm using doctrine & slim, the important part is the "autoload" section.  This section in particular is important.

```<code>"psr-0": {
            "WebSocketApp":"websockets"
        },
</code>```

This will autoload anything in the folder websockets in the namespace of WebSocketApp.  psr-0 assumed that code would be organized by folders for namespaces which is why we had to add another folder called WebSocketApp inside of websockets.

Step 5:

In the htmlserver.php file put this...

```<code><?php
namespace WebSocketApp;
use Guzzle\Http\Message\RequestInterface;
use Guzzle\Http\Message\Response;
use Guzzle\Http\Message\Request;
use Ratchet\ConnectionInterface;
use Ratchet\Http\HttpServerInterface;

class Htmlserver implements HttpServerInterface {
    protected $response;

    public function onOpen( ConnectionInterface $conn, RequestInterface $request = null ) {
        global $dispatcher;

        $this->response = new Response( 200, [
            'Content-Type' => 'text/html; charset=utf-8',
        ] );

        $query = $request->getQuery();
        parse_str($query, $get_array);//@JA - Convert query to variables in an array

        $json = json_encode($get_array);//@JA - Encode to JSON

        //@JA - Send JSON for what you want to do and the token representing the user & therefore connected user as well.
        $event = new ClientEvent($json);
        $dispatcher->dispatch("websocketserver.updateclient",$event);

        $this->response->setBody('{"message":"Successfully sent message to websocket server")');
        echo "HTTP Connection Triggered\n";
        $this->close( $conn );
    }

    public function onClose( ConnectionInterface $conn ) {
        echo "HTTP Connection Ended\n";
    }

    public function onError( ConnectionInterface $conn, \Exception $e ) {
        echo "HTTP Connection Error\n";
    }

    public function onMessage( ConnectionInterface $from, $msg ) {
        echo "HTTP Connection Message\n";
    }

    protected function close( ConnectionInterface $conn ) {
        $conn->send( $this->response );
        $conn->close();
    }
}
</code>```

The purpose of this file is to make communication to the WebSocket server simple through basic HTTP which I will show a demo of later using cURL from the PHP Web Server.  I designed this to propagate messages to the WebSocket server using Symfony's Event system and by looking at the Query String and converting it to a JSON string.  It could have also been kept as an array if you wish, but in my case I needed the JSON string.

Step 6:

Next in the clientevent.php put this code...

```<code><?php
namespace WebSocketApp;

use Symfony\Component\EventDispatcher\Event;

use Entity\User;
use Entity\Socket;

class Clientevent extends Event
{
    const NAME = 'clientevent';

    protected $user; //@JA - This returns type Entity\User

    public function __construct($json)
    {
        global $entityManager;

        $decoded = json_decode($json,true);
        switch($decoded["command"]){
            case "updatestatus":
                //Find out what the current 'active' & 'busy' states are for the userid given (assuming user id exists?)
                if(isset($decoded["userid"])){
                    $results = $entityManager->getRepository('Entity\User')->findBy(array('id' => $decoded["userid"]));
                    if(count($results)>0){
                        unset($this->user);//@JA - Clear the old reference
                        $this->user = $results[0]; //@JA - Store refernece to the user object
                        $entityManager->refresh($this->user); //@JA - Because result cache is used by default, this will make sure the data is new and therefore the socket objects with it
                    }
                }
                break;
        }
    }

    public function getUser()
    {
        return $this->user;
    }
}
</code>```

Note that the User and Socket entities are entities I created from Doctrine 2.  You can use whatever database you prefer.  In my case I am needing to send messages to particular users from the PHP Web Server based on their login tokens from the database.

Clientevent assumes JSON string of '{"command":"updatestatus","userid":"2"}'

You can set it up however you like though.

Step 7:

In the Websocketserver.php file put this...

```<code><?php
namespace WebSocketApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Symfony\Component\EventDispatcher\Event;

use Entity\User;
use Entity\Authtoken;
use Entity\Socket;

class Websocketserver implements MessageComponentInterface {
    protected $clients;

    public function updateClient(Event $event)
    {
       $user = $event->getUser();//@JA - Get reference to the user the event is for.

       echo "userid=".$user->getId()."\n";
       echo "busy=".($user->getBusy()==false ? "0" : "1")."\n";
       echo "active=".($user->getActive()==false ? "0" : "1")."\n";

       $json["busy"]    = ($user->getBusy()==false ? "0" : "1");
       $json["active"]  = ($user->getActive()==false ? "0" : "1");

       $msg = json_encode($json);

       foreach($user->getSockets() as $socket){
            $connectionid = $socket->getConnectionid();
            echo "Sending For ConnectionID:".$connectionid."\n";
            if(isset($this->clients[$connectionid])){
                $client = $this->clients[$connectionid];
                $client->send($msg);
            }else{
                echo "Client is no longer connected for this Connection ID:".$connectionid."\n";
            }
       }
    }

    public function __construct() {
        $this->clients = array();
    }

    public function onOpen(ConnectionInterface $conn) {
        // Store the new connection to send messages to later
        $this->clients[$conn->resourceId] = $conn;
        echo "New connection! ({$conn->resourceId})\n";
    }

    public function onMessage(ConnectionInterface $from, $msg) {
        global $entityManager;

        echo sprintf('Connection %d sending message "%s"' . "\n", $from->resourceId, $msg);

        //@JA - First step is to decode the message coming from the client.  Use token to identify the user (from cookie or local storage)
        //@JA - Format is JSON {token:58d8beeb0ada3:4ffbd272a1703a59ad82cddc2f592685135b09f2,message:register}
        $json = json_decode($msg,true);
        //echo 'json='.print_r($json,true)."\n";
        if($json["message"] == "register"){
            echo "Registering with server...\n";

            $parts = explode(":",$json["token"]);

            $selector = $parts[0];
            $validator = $parts[1];

            //@JA - Look up records in the database by selector.
            $tokens = $entityManager->getRepository('Entity\Authtoken')->findBy(array('selector' => $selector, 'token' => hash('sha256',$validator)));

            if(count($tokens)>0){
                $user = $tokens[0]->getUser();
                echo "User ID:".$user->getId()." Registered from given token\n";
                $socket = new Socket();
                $socket->setUser($user);
                $socket->setConnectionid($from->resourceId);
                $socket->setDatecreated(new \Datetime());

                $entityManager->persist($socket);
                $entityManager->flush();
            }else{
                echo "No user found from the given cookie token\n";
            }

        }else{
            echo "Unknown Message...\n";
        }
    }

    public function onClose(ConnectionInterface $conn) {
        global $entityManager;

        // The connection is closed, remove it, as we can no longer send it messages
        unset($this->clients[$conn->resourceId]);

        //@JA - We need to clean up the database of any loose ends as well so it doesn't get full with loose data
        $socketResults = $entityManager->getRepository('Entity\Socket')->findBy(array('connectionid' => $conn->resourceId));
        if(count($socketResults)>0){
            $socket = $socketResults[0];
            $entityManager->remove($socket);
            $entityManager->flush();
            echo "Socket Entity For Connection ID:".$conn->resourceId." Removed\n";
        }else{
            echo "Was no socket info to remove from database??\n";
        }

        echo "Connection {$conn->resourceId} has disconnected\n";
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
        echo "An error has occurred: {$e->getMessage()}\n";

        $conn->close();
    }
}
</code>```

This is the most complicated file to explain.  To start there is a protected variable clients that stores every connection made to this ratchet websocket server.  Its created in the onOpen event.

Next the onMessage event is where the web browser clients will register themselves for receiving messages.  I did this using a JSON protocol.  An example is in the code of the format I used in particular in which I used the token from their cookie to identify what user it was in my system along with a simple register message.

I simple look in the database in this function to see if there is an authToken to go along with the cookie.

If there is write to the Socket table in your database the $from->resourceId

This is the number that ratchet uses to keep track of that particular connection number.

Next in the onClose method note that we have to make sure to remove the entries we created when the connection closes so the database doesn't get filled with unnecessary and extra data.

Finally note that the updateClient function is a symfony Event that is triggered from the HtmlServer we did earlier.

This is what actually sends the message to the client web browser.  First in case that user has many web browsers open creating different connections we loop through all known sockets related to that user.  Doctrine makes this easy with $user->getSockets(), you will have to decide best way to do this.

Then you simply say $client->send($msg) to send the message to the web browser.

Step 8:

Finally in your javascript for your webbrowser put something like this.

```<code>var hostname = window.location.hostname; //@JA - Doing it this way will make this work on DEV and LIVE Enviroments
    var conn = new WebSocket('ws://'+hostname+':8080');
    conn.onopen = function(e) {
        console.log("Connection established!");
        //@JA - Register with the server so it associates the connection ID to the supplied token
        conn.send('{"token":"'+$.cookie("ccdraftandpermit")+'","message":"register"}');
    };

    conn.onmessage = function(e) {
        //@JA - Update in realtime the busy and active status
        console.log(e.data)
        var obj = jQuery.parseJSON(e.data);
        if(obj.busy == "0"){
            $('.status').attr("status","free");
            $('.status').html("Free");
            $(".unbusy").css("display","none");
        }else{
            $('.status').attr("status","busy");
            $('.status').html("Busy");
            $(".unbusy").css("display","inline");
        }
        if(obj.active == "0"){
            $('.startbtn').attr("status","off");
            $('.startbtn').html("Start Taking Calls");
        }else{
            $('.startbtn').attr("status","on");
            $('.startbtn').html("Stop Taking Calls");
        }
    };
</code>```

My demo here shows simple way to pass information back and forth with JSON.

Step 9:

To send messages from the PHP Web server I did something like this in a helper function.

```<code>function h_sendWebsocketNotificationToUser($userid){
    //Send notification out to Websocket Server
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "http://localhost/?command=updatestatus&userid=".$userid);
    curl_setopt($ch, CURLOPT_PORT, 6677);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $output = curl_exec($ch);
    curl_close($ch);
}
</code>```

This would attempt to send the updateStatus message for a particular user at anytime.

Step 10:

There is no step 10 you are done! Well okay not quite... To run the webserver in the background I use Docker which makes it easy.  Simply execute the webserver with the following command.

```<code>docker exec -itd draftandpermit_web_1 bash -c "cd /var/www/callcenter/livesite; php bin/startwebsocketserver.php"
</code>```

or something of this equivlent for your situation.  Key here is the -d option I'm using which runs it in the background.  Even if you run the command again it will NOT spawn two instances which is nifty.  Shutting down the server is outside the scope of this but if you find a nice way to do this please amend or comment on this answer.

Also don't forget to open the ports correctly on your docker-compose file.  I did something like this for my project.

```<code>ports:
            - "80:80"
            - "8080:8080"
            - "6060:80"
            - "443:443"
            - "6677:6677"
            #This is used below to test on local machines, just portforward this on your router.
            - "8082:80"
</code>```

Just remember 8080 is used by the WebSockets so it has to pass through completely.

In case you are curious about entity and database structure and what I used here is an attached image.

ContentLicense: CC BY-SA 3.0

Body:
I have been following along with the tutorials here and got the ratchet server working.

My chat class is the same as the tutorial more or less at the moment, so no point in showing that here yet since my question is more about implementation strategy.

In the question I attached the user was looking how to get the connection object of a specific user.  In the top answer solution keeping track of the resource IDs seems to be the way to do this.

For example when the connection is created there is this code.

public function onOpen(ConnectionInterface $conn) {
        // Store the new connection to send messages to later
        $this->clients[$conn->resourceId] = $conn;
        echo "New connection! ({$conn->resourceId})\n";
    }

This creates a member variable clients to store all the connections and you simply reference it now by ID to send a message.  This clients however is an instance of ConnectionInterface $conn

Then to send a message you simply use the code below entering as the array key the id of the client.  Very simple.

$client = $this->clients[{{insert client id here}}];
$client->send("Message successfully sent to user.");

As we know ratchet runs as a script on the server in an event loop never ending.

I'm running a Symfony project in which outside of the server instance running the ratchet code when a user does a certain action in the system I need it to send a message to a particular client connected to the server.

I'm not sure how to do this since the clients are instances of ConnectionInterface and are created when the users first connect via WebSockets. How do I send a message to a particular client in this way?

Here is a visual of what I'm trying to achieve.

References:

how to get the connection object of a specific user?

Body:
The solution I am about to post covers the entire process of communicating from server to the client on the web browser including a way to make the Websocket server run in the background (with and without docker).

Step 1:

Assuming you have ratchet installed via composer, create a folder in your project called bin and name the file "startwebsocketserver.php" (or whatever you want)

Step 2:

Copy the following code into it.

<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use React\Socket\Server;
use React\EventLoop\Factory;

use WebSocketApp\Websocketserver;
use WebSocketApp\Htmlserver;
use WebSocketApp\Clientevent;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Ratchet\App;

require dirname(__DIR__) . '/vendor/autoload.php';
require_once dirname(__DIR__) . '/bootstrap/bootstrap.php';

$websocketserver = new Websocketserver();

$dispatcher = new EventDispatcher(); //@JA - This is used to maintain communication between the websocket and HTTP Rest API Server
$dispatcher->addListener('websocketserver.updateclient', array($websocketserver, 'updateClient'));

//// 1. Create the event loop
$loop = Factory::create();

//// 2. Create websocket servers
$webSock = new Server($loop);
new IoServer(
    new HttpServer(
        new WsServer( $websocketserver )
    ),
    $webSock
);
$webSock->listen('8080', '0.0.0.0');

$app = new App( 'localhost', 6677, '0.0.0.0',$loop );
$app->route( '/', new Htmlserver(), [ '*' ] );//@JA - Allow any origins for last parameter

$app->run();

Note that in my example I am using a bootstrap file to load the database.  If you are not using a database or some other method than ignore that.  For the purposes of this answer I will be assuming Doctrine 2 as the database.

What this code does is creates an HTTP server & a WebSocket server within the same code base and at the same time.  I'm using the $app->route approach since you can add further routing for the HTTP server to organize API Calls to talk to the WebSocket Server from your PHP Web Server.

The $loop variable includes the Websocket server in the application loop along with the HTTPServer.

Step 3:

In your project directory create a folder called websockets.  Inside that create another folder called WebSocketApp.  Inside that create 3 empty files for now.

Clientevent.php
Htmlserver.php
Websocketserver.php

We will go into each of these files 1 by 1 next.  Failure to create these directories in this order will cause composer Autoload PSR-0 to fail to find them.

You can change the names but make sure you edit your composer file accordingly.

Step 4:

In your composer.json file make sure it looks something like this.

{
    "require": {
        "doctrine/orm": "^2.5",
        "slim/slim": "^3.0",
        "slim/twig-view": "^2.1",
        "components/jquery": "*",
        "components/normalize.css": "*",
        "robloach/component-installer": "*",
        "paragonie/random_compat": "^2.0",
        "twilio/sdk": "^5.5",
        "aws/aws-sdk-php": "^3.22",
        "mailgun/mailgun-php": "^2.1",
        "php-http/curl-client": "^1.7",
        "guzzlehttp/psr7": "^1.3",
        "cboden/ratchet": "^0.3.6"
    },
    "autoload": {
        "psr-4": {
            "app\\":"app",
            "Entity\\":"entities"
        },
        "psr-0": {
            "WebSocketApp":"websockets"
        },
        "files": ["lib/utilities.php","lib/security.php"]
    }
}

In my case I'm using doctrine & slim, the important part is the "autoload" section.  This section in particular is important.

"psr-0": {
            "WebSocketApp":"websockets"
        },

This will autoload anything in the folder websockets in the namespace of WebSocketApp.  psr-0 assumed that code would be organized by folders for namespaces which is why we had to add another folder called WebSocketApp inside of websockets.

Step 5:

In the htmlserver.php file put this...

<?php
namespace WebSocketApp;
use Guzzle\Http\Message\RequestInterface;
use Guzzle\Http\Message\Response;
use Guzzle\Http\Message\Request;
use Ratchet\ConnectionInterface;
use Ratchet\Http\HttpServerInterface;

class Htmlserver implements HttpServerInterface {
    protected $response;

    public function onOpen( ConnectionInterface $conn, RequestInterface $request = null ) {
        global $dispatcher;

        $this->response = new Response( 200, [
            'Content-Type' => 'text/html; charset=utf-8',
        ] );

        $query = $request->getQuery();
        parse_str($query, $get_array);//@JA - Convert query to variables in an array

        $json = json_encode($get_array);//@JA - Encode to JSON

        //@JA - Send JSON for what you want to do and the token representing the user & therefore connected user as well.
        $event = new ClientEvent($json);
        $dispatcher->dispatch("websocketserver.updateclient",$event);

        $this->response->setBody('{"message":"Successfully sent message to websocket server")');
        echo "HTTP Connection Triggered\n";
        $this->close( $conn );
    }

    public function onClose( ConnectionInterface $conn ) {
        echo "HTTP Connection Ended\n";
    }

    public function onError( ConnectionInterface $conn, \Exception $e ) {
        echo "HTTP Connection Error\n";
    }

    public function onMessage( ConnectionInterface $from, $msg ) {
        echo "HTTP Connection Message\n";
    }

    protected function close( ConnectionInterface $conn ) {
        $conn->send( $this->response );
        $conn->close();
    }
}

The purpose of this file is to make communication to the WebSocket server simple through basic HTTP which I will show a demo of later using cURL from the PHP Web Server.  I designed this to propagate messages to the WebSocket server using Symfony's Event system and by looking at the Query String and converting it to a JSON string.  It could have also been kept as an array if you wish, but in my case I needed the JSON string.

Step 6:

Next in the clientevent.php put this code...

<?php
namespace WebSocketApp;

use Symfony\Component\EventDispatcher\Event;

use Entity\User;
use Entity\Socket;

class Clientevent extends Event
{
    const NAME = 'clientevent';

    protected $user; //@JA - This returns type Entity\User

    public function __construct($json)
    {
        global $entityManager;

        $decoded = json_decode($json,true);
        switch($decoded["command"]){
            case "updatestatus":
                //Find out what the current 'active' & 'busy' states are for the userid given (assuming user id exists?)
                if(isset($decoded["userid"])){
                    $results = $entityManager->getRepository('Entity\User')->findBy(array('id' => $decoded["userid"]));
                    if(count($results)>0){
                        unset($this->user);//@JA - Clear the old reference
                        $this->user = $results[0]; //@JA - Store refernece to the user object
                        $entityManager->refresh($this->user); //@JA - Because result cache is used by default, this will make sure the data is new and therefore the socket objects with it
                    }
                }
                break;
        }
    }

    public function getUser()
    {
        return $this->user;
    }
}

Note that the User and Socket entities are entities I created from Doctrine 2.  You can use whatever database you prefer.  In my case I am needing to send messages to particular users from the PHP Web Server based on their login tokens from the database.

Clientevent assumes JSON string of '{"command":"updatestatus","userid":"2"}'

You can set it up however you like though.

Step 7:

In the Websocketserver.php file put this...

<?php
namespace WebSocketApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Symfony\Component\EventDispatcher\Event;

use Entity\User;
use Entity\Authtoken;
use Entity\Socket;

class Websocketserver implements MessageComponentInterface {
    protected $clients;

    public function updateClient(Event $event)
    {
       $user = $event->getUser();//@JA - Get reference to the user the event is for.

       echo "userid=".$user->getId()."\n";
       echo "busy=".($user->getBusy()==false ? "0" : "1")."\n";
       echo "active=".($user->getActive()==false ? "0" : "1")."\n";

       $json["busy"]    = ($user->getBusy()==false ? "0" : "1");
       $json["active"]  = ($user->getActive()==false ? "0" : "1");

       $msg = json_encode($json);

       foreach($user->getSockets() as $socket){
            $connectionid = $socket->getConnectionid();
            echo "Sending For ConnectionID:".$connectionid."\n";
            if(isset($this->clients[$connectionid])){
                $client = $this->clients[$connectionid];
                $client->send($msg);
            }else{
                echo "Client is no longer connected for this Connection ID:".$connectionid."\n";
            }
       }
    }

    public function __construct() {
        $this->clients = array();
    }

    public function onOpen(ConnectionInterface $conn) {
        // Store the new connection to send messages to later
        $this->clients[$conn->resourceId] = $conn;
        echo "New connection! ({$conn->resourceId})\n";
    }

    public function onMessage(ConnectionInterface $from, $msg) {
        global $entityManager;

        echo sprintf('Connection %d sending message "%s"' . "\n", $from->resourceId, $msg);

        //@JA - First step is to decode the message coming from the client.  Use token to identify the user (from cookie or local storage)
        //@JA - Format is JSON {token:58d8beeb0ada3:4ffbd272a1703a59ad82cddc2f592685135b09f2,message:register}
        $json = json_decode($msg,true);
        //echo 'json='.print_r($json,true)."\n";
        if($json["message"] == "register"){
            echo "Registering with server...\n";

            $parts = explode(":",$json["token"]);

            $selector = $parts[0];
            $validator = $parts[1];

            //@JA - Look up records in the database by selector.
            $tokens = $entityManager->getRepository('Entity\Authtoken')->findBy(array('selector' => $selector, 'token' => hash('sha256',$validator)));

            if(count($tokens)>0){
                $user = $tokens[0]->getUser();
                echo "User ID:".$user->getId()." Registered from given token\n";
                $socket = new Socket();
                $socket->setUser($user);
                $socket->setConnectionid($from->resourceId);
                $socket->setDatecreated(new \Datetime());

                $entityManager->persist($socket);
                $entityManager->flush();
            }else{
                echo "No user found from the given cookie token\n";
            }

        }else{
            echo "Unknown Message...\n";
        }
    }

    public function onClose(ConnectionInterface $conn) {
        global $entityManager;

        // The connection is closed, remove it, as we can no longer send it messages
        unset($this->clients[$conn->resourceId]);

        //@JA - We need to clean up the database of any loose ends as well so it doesn't get full with loose data
        $socketResults = $entityManager->getRepository('Entity\Socket')->findBy(array('connectionid' => $conn->resourceId));
        if(count($socketResults)>0){
            $socket = $socketResults[0];
            $entityManager->remove($socket);
            $entityManager->flush();
            echo "Socket Entity For Connection ID:".$conn->resourceId." Removed\n";
        }else{
            echo "Was no socket info to remove from database??\n";
        }

        echo "Connection {$conn->resourceId} has disconnected\n";
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
        echo "An error has occurred: {$e->getMessage()}\n";

        $conn->close();
    }
}

This is the most complicated file to explain.  To start there is a protected variable clients that stores every connection made to this ratchet websocket server.  Its created in the onOpen event.

Next the onMessage event is where the web browser clients will register themselves for receiving messages.  I did this using a JSON protocol.  An example is in the code of the format I used in particular in which I used the token from their cookie to identify what user it was in my system along with a simple register message.

I simple look in the database in this function to see if there is an authToken to go along with the cookie.

If there is write to the Socket table in your database the $from->resourceId

This is the number that ratchet uses to keep track of that particular connection number.

Next in the onClose method note that we have to make sure to remove the entries we created when the connection closes so the database doesn't get filled with unnecessary and extra data.

Finally note that the updateClient function is a symfony Event that is triggered from the HtmlServer we did earlier.

This is what actually sends the message to the client web browser.  First in case that user has many web browsers open creating different connections we loop through all known sockets related to that user.  Doctrine makes this easy with $user->getSockets(), you will have to decide best way to do this.

Then you simply say $client->send($msg) to send the message to the web browser.

Step 8:

Finally in your javascript for your webbrowser put something like this.

var hostname = window.location.hostname; //@JA - Doing it this way will make this work on DEV and LIVE Enviroments
    var conn = new WebSocket('ws://'+hostname+':8080');
    conn.onopen = function(e) {
        console.log("Connection established!");
        //@JA - Register with the server so it associates the connection ID to the supplied token
        conn.send('{"token":"'+$.cookie("ccdraftandpermit")+'","message":"register"}');
    };

    conn.onmessage = function(e) {
        //@JA - Update in realtime the busy and active status
        console.log(e.data)
        var obj = jQuery.parseJSON(e.data);
        if(obj.busy == "0"){
            $('.status').attr("status","free");
            $('.status').html("Free");
            $(".unbusy").css("display","none");
        }else{
            $('.status').attr("status","busy");
            $('.status').html("Busy");
            $(".unbusy").css("display","inline");
        }
        if(obj.active == "0"){
            $('.startbtn').attr("status","off");
            $('.startbtn').html("Start Taking Calls");
        }else{
            $('.startbtn').attr("status","on");
            $('.startbtn').html("Stop Taking Calls");
        }
    };

My demo here shows simple way to pass information back and forth with JSON.

Step 9:

To send messages from the PHP Web server I did something like this in a helper function.

function h_sendWebsocketNotificationToUser($userid){
    //Send notification out to Websocket Server
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "http://localhost/?command=updatestatus&userid=".$userid);
    curl_setopt($ch, CURLOPT_PORT, 6677);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $output = curl_exec($ch);
    curl_close($ch);
}

This would attempt to send the updateStatus message for a particular user at anytime.

Step 10:

There is no step 10 you are done! Well okay not quite... To run the webserver in the background I use Docker which makes it easy.  Simply execute the webserver with the following command.

docker exec -itd draftandpermit_web_1 bash -c "cd /var/www/callcenter/livesite; php bin/startwebsocketserver.php"

or something of this equivlent for your situation.  Key here is the -d option I'm using which runs it in the background.  Even if you run the command again it will NOT spawn two instances which is nifty.  Shutting down the server is outside the scope of this but if you find a nice way to do this please amend or comment on this answer.

Also don't forget to open the ports correctly on your docker-compose file.  I did something like this for my project.

ports:
            - "80:80"
            - "8080:8080"
            - "6060:80"
            - "443:443"
            - "6677:6677"
            #This is used below to test on local machines, just portforward this on your router.
            - "8082:80"

Just remember 8080 is used by the WebSockets so it has to pass through completely.

In case you are curious about entity and database structure and what I used here is an attached image.


问:
Worksheets.Add in UDF Not Working
I have a UDF that can be called from within a cell in my excel workbook. I need it to add a worksheet at the end of the workbook. I have used sheets.add multiple times in my VBA script, but never in a function called from inside a cell and this is apparently causing some issue.

The function accepts an optional parameter for file path of the workbook in which to add the sheet, and if the user leaves this blank I want to default to the active workbook.

Below is the relevant code... What am I doing wrong?

```<code>Public Function onesheet(Optional filepath As String)

Dim wb As Workbook
Dim ws As Worksheet

If filepath = "" Then
   Set wb = ActiveWorkbook
   Set target_ws = wb.Sheets.Add(after:=wb.Sheets(wb.Sheets.Count))
End If
</code>```

The function is being called from the cell with
=onesheet()

答:
A function (UDF) has one role: compute a value and return that value to the cell (or formula/expression) that called it.

This is a function:

```<code>Public Function Foo(ByVal bar As String) As String
    Foo = "Hello, " & bar
End Function
</code>```

You can use it in a worksheet cell like this:

```<code>=Foo("dsdavidson")
</code>```

And every time Excel recalculates that cell's value, it calls the UDF, making the cell's value read Hello, dsdavidson.

Functions don't have side-effects. Functions don't modify other cells. Functions take input, process it, and output a result.

What you're doing wrong, is using a UDF as if it were a macro.

Change your Function for a Sub, and don't call it from within a cell. Make a button to call it instead. Or whatever rocks your boat. But you can't have a cell formula that adds a worksheet to the workbook every time it recalculates.

Macros need to be Public and parameterless. So you'll want to take your optional parameter value from a specific cell, or display a form that lets the user pick from a list of available opened workbooks - and then call your procedure and pass the user's selection as a parameter.

Quite possibly the macro code could end up looking something like this (YMMV):

```<code>Public Sub AddWorksheet()
    With New PromptForm
        .Show
        If .Cancelled Then Exit Sub
        OneSheet .SelectedBook
    End With
End Sub
</code>```

Title: Worksheets.Add in UDF Not Working

Body:
I have a UDF that can be called from within a cell in my excel workbook. I need it to add a worksheet at the end of the workbook. I have used sheets.add multiple times in my VBA script, but never in a function called from inside a cell and this is apparently causing some issue.

The function accepts an optional parameter for file path of the workbook in which to add the sheet, and if the user leaves this blank I want to default to the active workbook.

Below is the relevant code... What am I doing wrong?

Public Function onesheet(Optional filepath As String)

Dim wb As Workbook
Dim ws As Worksheet

If filepath = "" Then
   Set wb = ActiveWorkbook
   Set target_ws = wb.Sheets.Add(after:=wb.Sheets(wb.Sheets.Count))
End If

The function is being called from the cell with
=onesheet()

Body:
A function (UDF) has one role: compute a value and return that value to the cell (or formula/expression) that called it.

This is a function:

Public Function Foo(ByVal bar As String) As String
    Foo = "Hello, " & bar
End Function

You can use it in a worksheet cell like this:

=Foo("dsdavidson")

And every time Excel recalculates that cell's value, it calls the UDF, making the cell's value read Hello, dsdavidson.

Functions don't have side-effects. Functions don't modify other cells. Functions take input, process it, and output a result.

What you're doing wrong, is using a UDF as if it were a macro.

Change your Function for a Sub, and don't call it from within a cell. Make a button to call it instead. Or whatever rocks your boat. But you can't have a cell formula that adds a worksheet to the workbook every time it recalculates.

Macros need to be Public and parameterless. So you'll want to take your optional parameter value from a specific cell, or display a form that lets the user pick from a list of available opened workbooks - and then call your procedure and pass the user's selection as a parameter.

Quite possibly the macro code could end up looking something like this (YMMV):

Public Sub AddWorksheet()
    With New PromptForm
        .Show
        If .Cancelled Then Exit Sub
        OneSheet .SelectedBook
    End With
End Sub


问:
Collecting data about product in cookie using Jquery
I would like to check if cookie exist and if not create one which will collect information about last 3 products seen on the page (url, picture).
When visitor will come back I would like to show him inside slider these three products.
Many thanks for any help.</p>

答:
There is a cookie framework from mozilla.org:

cookie_framework MDN

```<code>/*\
|*|
|*|  :: cookies.js ::
|*|
|*|  A complete cookies reader/writer framework with full unicode support.
|*|
|*|  Revision #1 - September 4, 2014
|*|
|*|  https://developer.mozilla.org/en-US/docs/Web/API/document.cookie
|*|  https://developer.mozilla.org/User:fusionchess
|*|  https://github.com/madmurphy/cookies.js
|*|
|*|  This framework is released under the GNU Public License, version 3 or later.
|*|  http://www.gnu.org/licenses/gpl-3.0-standalone.html
|*|
|*|  Syntaxes:
|*|
|*|  * docCookies.setItem(name, value[, end[, path[, domain[, secure]]]])
|*|  * docCookies.getItem(name)
|*|  * docCookies.removeItem(name[, path[, domain]])
|*|  * docCookies.hasItem(name)
|*|  * docCookies.keys()
|*|
\*/

var docCookies = {
  getItem: function (sKey) {
    if (!sKey) { return null; }
    return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
  },
  setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
    if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; }
    var sExpires = "";
    if (vEnd) {
      switch (vEnd.constructor) {
        case Number:
          sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd;
          break;
        case String:
          sExpires = "; expires=" + vEnd;
          break;
        case Date:
          sExpires = "; expires=" + vEnd.toUTCString();
          break;
      }
    }
    document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "");
    return true;
  },
  removeItem: function (sKey, sPath, sDomain) {
    if (!this.hasItem(sKey)) { return false; }
    document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "");
    return true;
  },
  hasItem: function (sKey) {
    if (!sKey) { return false; }
    return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
  },
  keys: function () {
    var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/);
    for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) { aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); }
    return aKeys;
  }
};
</code>```

Example:

```<code>docCookies.setItem("test0", "Hello world!");
docCookies.setItem("test1", "Unicode test: \u00E0\u00E8\u00EC\u00F2\u00F9", Infinity);
docCookies.setItem("test2", "Hello world!", new Date(2020, 5, 12));
docCookies.setItem("test3", "Hello world!", new Date(2027, 2, 3), "/blog");
docCookies.setItem("test4", "Hello world!", "Wed, 19 Feb 2127 01:04:55 GMT");
docCookies.setItem("test5", "Hello world!", "Fri, 20 Aug 88354 14:07:15 GMT", "/home");
docCookies.setItem("test6", "Hello world!", 150);
docCookies.setItem("test7", "Hello world!", 245, "/content");
docCookies.setItem("test8", "Hello world!", null, null, "example.com");
docCookies.setItem("test9", "Hello world!", null, null, null, true);
docCookies.setItem("test1;=", "Safe character test;=", Infinity);

alert(docCookies.keys().join("\n"));
alert(docCookies.getItem("test1"));
alert(docCookies.getItem("test5"));
docCookies.removeItem("test1");
docCookies.removeItem("test5", "/home");
alert(docCookies.getItem("test1"));
alert(docCookies.getItem("test5"));
alert(docCookies.getItem("unexistingCookie"));
alert(docCookies.getItem());
alert(docCookies.getItem("test1;="));
</code>```

Body:
There is a cookie framework from mozilla.org:

cookie_framework MDN

/*\
|*|
|*|  :: cookies.js ::
|*|
|*|  A complete cookies reader/writer framework with full unicode support.
|*|
|*|  Revision #1 - September 4, 2014
|*|
|*|  https://developer.mozilla.org/en-US/docs/Web/API/document.cookie
|*|  https://developer.mozilla.org/User:fusionchess
|*|  https://github.com/madmurphy/cookies.js
|*|
|*|  This framework is released under the GNU Public License, version 3 or later.
|*|  http://www.gnu.org/licenses/gpl-3.0-standalone.html
|*|
|*|  Syntaxes:
|*|
|*|  * docCookies.setItem(name, value[, end[, path[, domain[, secure]]]])
|*|  * docCookies.getItem(name)
|*|  * docCookies.removeItem(name[, path[, domain]])
|*|  * docCookies.hasItem(name)
|*|  * docCookies.keys()
|*|
\*/

var docCookies = {
  getItem: function (sKey) {
    if (!sKey) { return null; }
    return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
  },
  setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
    if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; }
    var sExpires = "";
    if (vEnd) {
      switch (vEnd.constructor) {
        case Number:
          sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd;
          break;
        case String:
          sExpires = "; expires=" + vEnd;
          break;
        case Date:
          sExpires = "; expires=" + vEnd.toUTCString();
          break;
      }
    }
    document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "");
    return true;
  },
  removeItem: function (sKey, sPath, sDomain) {
    if (!this.hasItem(sKey)) { return false; }
    document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "");
    return true;
  },
  hasItem: function (sKey) {
    if (!sKey) { return false; }
    return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
  },
  keys: function () {
    var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/);
    for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) { aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); }
    return aKeys;
  }
};

Example:

docCookies.setItem("test0", "Hello world!");
docCookies.setItem("test1", "Unicode test: \u00E0\u00E8\u00EC\u00F2\u00F9", Infinity);
docCookies.setItem("test2", "Hello world!", new Date(2020, 5, 12));
docCookies.setItem("test3", "Hello world!", new Date(2027, 2, 3), "/blog");
docCookies.setItem("test4", "Hello world!", "Wed, 19 Feb 2127 01:04:55 GMT");
docCookies.setItem("test5", "Hello world!", "Fri, 20 Aug 88354 14:07:15 GMT", "/home");
docCookies.setItem("test6", "Hello world!", 150);
docCookies.setItem("test7", "Hello world!", 245, "/content");
docCookies.setItem("test8", "Hello world!", null, null, "example.com");
docCookies.setItem("test9", "Hello world!", null, null, null, true);
docCookies.setItem("test1;=", "Safe character test;=", Infinity);

alert(docCookies.keys().join("\n"));
alert(docCookies.getItem("test1"));
alert(docCookies.getItem("test5"));
docCookies.removeItem("test1");
docCookies.removeItem("test5", "/home");
alert(docCookies.getItem("test1"));
alert(docCookies.getItem("test5"));
alert(docCookies.getItem("unexistingCookie"));
alert(docCookies.getItem());
alert(docCookies.getItem("test1;="));


问:
Jboss 7 hibernate module is not finding persistence xml classes
I am trying to migrate my project from JSF1.2, Hibernate 3.x, Jboss 4.3 to JSF 2.1, Hibernate 4.x and Jboss EAP 6.3.  During startup, I get an error saying that
    `

```<code>10:46:35,776 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 48) MSC000001: Failed to start service jboss.persistenceunit."MyEAR.ear#myJPA": org.jboss.msc.service.StartException in service jboss.persistenceunit."MyEAR.ear#myJPA": javax.persistence.PersistenceException: [PersistenceUnit: myJPA] class or package not found
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1.run(PersistenceUnitServiceImpl.java:103) [jboss-as-jpa-7.4.0.Final-redhat-19.jar:7.4.0.Final-redhat-19]
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) [rt.jar:1.6.0_45]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918) [rt.jar:1.6.0_45]
    at java.lang.Thread.run(Thread.java:662) [rt.jar:1.6.0_45]
    at org.jboss.threads.JBossThread.run(JBossThread.java:122) [jboss-threads-2.1.1.Final-redhat-1.jar:2.1.1.Final-redhat-1]
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: myJPA] class or package not found
    at org.hibernate.ejb.Ejb3Configuration.addNamedAnnotatedClasses(Ejb3Configuration.java:1410)
    at org.hibernate.ejb.Ejb3Configuration.addClassesToSessionFactory(Ejb3Configuration.java:1193)
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:1057)
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:702)
    at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:75)
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.createContainerEntityManagerFactory(PersistenceUnitServiceImpl.java:200) [jboss-as-jpa-7.4.0.Final-redhat-19.jar:7.4.0.Final-redhat-19]
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.access$600(PersistenceUnitServiceImpl.java:57) [jboss-as-jpa-7.4.0.Final-redhat-19.jar:7.4.0.Final-redhat-19]
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1.run(PersistenceUnitServiceImpl.java:99) [jboss-as-jpa-7.4.0.Final-redhat-19.jar:7.4.0.Final-redhat-19]
    ... 4 more
Caused by: java.lang.ClassNotFoundException:
        com.xxx.persistence.Agent from [Module "org.hibernate:main" from local module loader @26a3960 (finder: local module finder @bdccedd (roots: C:\JbossEAP6.3\jboss-eap-6.3\modules,C:\JbossEAP6.3\jboss-eap-6.3\modules\system\layers\base))]
    at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:213) [jboss-modules.jar:1.3.3.Final-redhat-1]
    at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:459) [jboss-modules.jar:1.3.3.Final-redhat-1]
    at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:447) [jboss-modules.jar:1.3.3.Final-redhat-1]
    at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:414) [jboss-modules.jar:1.3.3.Final-redhat-1]
    at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:389) [jboss-modules.jar:1.3.3.Final-redhat-1]
    at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:134) [jboss-modules.jar:1.3.3.Final-redhat-1]
    at java.lang.Class.forName0(Native Method) [rt.jar:1.6.0_45]
    at java.lang.Class.forName(Class.java:249) [rt.jar:1.6.0_45]
    at org.hibernate.internal.util.ReflectHelper.classForName(ReflectHelper.java:170)
    at org.hibernate.ejb.Ejb3Configuration.classForName(Ejb3Configuration.java:1327)
    at org.hibernate.ejb.Ejb3Configuration.addNamedAnnotatedClasses(Ejb3Configuration.java:1399)
    ... 11 more
</code>```

`

My EAR structure is as below.

MyEAR.ear

MyWAR.war (persistence unit myJPA is present in web-inf/classes/meta-inf)

MyEJB.jar (persistence unit myJPA is present in META-INF)

lib/MyJPA.jar (persistence unit myJPA is present in META-INF)

META-INF

My jboss-deployment-structure.xml is as below.
    `

```<code><jboss-deployment-structure>
    <deployment>
        <dependencies>
          <module name="deployment.MyJPA" />
        </dependencies>
        <resources>
            <resource-root path="MyJPA.jar" />
        </resources>
    </deployment>
    <sub-deployment name="MyWAR.war">
        <dependencies>
          <module name="deployment.MyEAR.ear.MyEJB.jar" />
          <module name="deployment.MyJPA" />
        </dependencies>
    </sub-deployment>
    <sub-deployment name="MyEJB.jar">
        <dependencies>
          <module name="deployment.MyJPA" />
        </dependencies>
    </sub-deployment>
    <module name="deployment.MyJPA" >
        <resources>
            <resource-root path="lib/MyJPA.jar"/>
        </resources>
    </module>
</jboss-deployment-structure>
</code>```

`
I am new to Jboss 7 so please let me know if my setup is not correct.

答:
So after lot of digging around and reading about the migration, it turns out that hibernate bundled with jboss could not read my persistence.xml properly. My persistence xml had classes written with carriage returns like below.

```<code><class>
com.someClass
</class>
</code>```

I believe the hibernate was including the newline/carriage return in the class name and hence not finding it. It was working fine in the previous hibernate 3.
While I understand that my formatting was not proper, I would expect hibernate to trim and use the class names. Anyways, my issue is resolved and hopefully someone finds this helpful.

Body:
I am trying to migrate my project from JSF1.2, Hibernate 3.x, Jboss 4.3 to JSF 2.1, Hibernate 4.x and Jboss EAP 6.3.  During startup, I get an error saying that
    `

10:46:35,776 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 48) MSC000001: Failed to start service jboss.persistenceunit."MyEAR.ear#myJPA": org.jboss.msc.service.StartException in service jboss.persistenceunit."MyEAR.ear#myJPA": javax.persistence.PersistenceException: [PersistenceUnit: myJPA] class or package not found
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1.run(PersistenceUnitServiceImpl.java:103) [jboss-as-jpa-7.4.0.Final-redhat-19.jar:7.4.0.Final-redhat-19]
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) [rt.jar:1.6.0_45]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918) [rt.jar:1.6.0_45]
    at java.lang.Thread.run(Thread.java:662) [rt.jar:1.6.0_45]
    at org.jboss.threads.JBossThread.run(JBossThread.java:122) [jboss-threads-2.1.1.Final-redhat-1.jar:2.1.1.Final-redhat-1]
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: myJPA] class or package not found
    at org.hibernate.ejb.Ejb3Configuration.addNamedAnnotatedClasses(Ejb3Configuration.java:1410)
    at org.hibernate.ejb.Ejb3Configuration.addClassesToSessionFactory(Ejb3Configuration.java:1193)
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:1057)
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:702)
    at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:75)
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.createContainerEntityManagerFactory(PersistenceUnitServiceImpl.java:200) [jboss-as-jpa-7.4.0.Final-redhat-19.jar:7.4.0.Final-redhat-19]
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.access$600(PersistenceUnitServiceImpl.java:57) [jboss-as-jpa-7.4.0.Final-redhat-19.jar:7.4.0.Final-redhat-19]
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1.run(PersistenceUnitServiceImpl.java:99) [jboss-as-jpa-7.4.0.Final-redhat-19.jar:7.4.0.Final-redhat-19]
    ... 4 more
Caused by: java.lang.ClassNotFoundException:
        com.xxx.persistence.Agent from [Module "org.hibernate:main" from local module loader @26a3960 (finder: local module finder @bdccedd (roots: C:\JbossEAP6.3\jboss-eap-6.3\modules,C:\JbossEAP6.3\jboss-eap-6.3\modules\system\layers\base))]
    at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:213) [jboss-modules.jar:1.3.3.Final-redhat-1]
    at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:459) [jboss-modules.jar:1.3.3.Final-redhat-1]
    at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:447) [jboss-modules.jar:1.3.3.Final-redhat-1]
    at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:414) [jboss-modules.jar:1.3.3.Final-redhat-1]
    at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:389) [jboss-modules.jar:1.3.3.Final-redhat-1]
    at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:134) [jboss-modules.jar:1.3.3.Final-redhat-1]
    at java.lang.Class.forName0(Native Method) [rt.jar:1.6.0_45]
    at java.lang.Class.forName(Class.java:249) [rt.jar:1.6.0_45]
    at org.hibernate.internal.util.ReflectHelper.classForName(ReflectHelper.java:170)
    at org.hibernate.ejb.Ejb3Configuration.classForName(Ejb3Configuration.java:1327)
    at org.hibernate.ejb.Ejb3Configuration.addNamedAnnotatedClasses(Ejb3Configuration.java:1399)
    ... 11 more

`

My EAR structure is as below.

MyEAR.ear

MyWAR.war (persistence unit myJPA is present in web-inf/classes/meta-inf)

MyEJB.jar (persistence unit myJPA is present in META-INF)

lib/MyJPA.jar (persistence unit myJPA is present in META-INF)

META-INF

My jboss-deployment-structure.xml is as below.
    `

<jboss-deployment-structure>
    <deployment>
        <dependencies>
          <module name="deployment.MyJPA" />
        </dependencies>
        <resources>
            <resource-root path="MyJPA.jar" />
        </resources>
    </deployment>

        <dependencies>
          <module name="deployment.MyEAR.ear.MyEJB.jar" />
          <module name="deployment.MyJPA" />
        </dependencies>

        <dependencies>
          <module name="deployment.MyJPA" />
        </dependencies>

    <module name="deployment.MyJPA" >
        <resources>
            <resource-root path="lib/MyJPA.jar"/>
        </resources>
    </module>
</jboss-deployment-structure>

`
I am new to Jboss 7 so please let me know if my setup is not correct.

Body:
So after lot of digging around and reading about the migration, it turns out that hibernate bundled with jboss could not read my persistence.xml properly. My persistence xml had classes written with carriage returns like below.

<class>
com.someClass
</class>

I believe the hibernate was including the newline/carriage return in the class name and hence not finding it. It was working fine in the previous hibernate 3.
While I understand that my formatting was not proper, I would expect hibernate to trim and use the class names. Anyways, my issue is resolved and hopefully someone finds this helpful.


问:
Android Studio: connecting to MongoDB server with Mongo Java Driver
There's a lot of posts about this problem, but noone seems to work, so maby some things have changed.

I am trying to connect my android application to a MongoDB server located on mLab. I'm using Mongo Java Drived and have off course added the library to android studio.

It is possible to start the app, but when I click on the register button the application craches.

Here's my code:

```<code>import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import org.bson.Document;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final EditText username = (EditText)findViewById(R.id.username);
    final Button bRegister = (Button) findViewById(R.id.bRegister);

    bRegister.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            String stringUsername = username.toString();
            try {
                addToDatabase(stringUsername);
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    });
}

private static void addToDatabase(String username){
    MongoClientURI uri  = new MongoClientURI("mongodb:///*mLab database URL */");
    MongoClient client = new MongoClient(uri);
    MongoDatabase db = client.getDatabase(uri.getDatabase());
    MongoCollection<Document> coll = db.getCollection("newDB");

    Document doc = new Document("username", username);
    coll.insertOne(doc);
    client.close();
}
}
</code>```

I also have permision.INTERNET in the manifest file.

Any help would be very appreciated!

//Edit
Stacktrace:

```<code>03/10 02:43:09: Launching app
Cold swapped changes.
$ adb shell am start -n "com.newhdc.pedergb.mongodb_servertester/com.newhdc.pedergb.mongodb_servertester.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Client not ready yet..Waiting for process to come online
Connected to process 4752 on device emulator-5554
D/NetworkSecurityConfig: No Network Security Config specified, using platform default
W/org.bson.ObjectId: Failed to get process identifier from JMX, using random number instead
                     java.lang.NoClassDefFoundError: Failed resolution of: Ljava/lang/management/ManagementFactory;
                         at org.bson.types.ObjectId.createProcessIdentifier(ObjectId.java:533)
                         at org.bson.types.ObjectId.<clinit>(ObjectId.java:491)
                         at com.mongodb.connection.ClusterId.<init>(ClusterId.java:47)
                         at com.mongodb.connection.DefaultClusterFactory.create(DefaultClusterFactory.java:105)
                         at com.mongodb.Mongo.createCluster(Mongo.java:744)
                         at com.mongodb.Mongo.createCluster(Mongo.java:728)
                         at com.mongodb.Mongo.createCluster(Mongo.java:702)
                         at com.mongodb.Mongo.<init>(Mongo.java:310)
                         at com.mongodb.Mongo.<init>(Mongo.java:306)
                         at com.mongodb.MongoClient.<init>(MongoClient.java:284)
                         at com.newhdc.pedergb.mongodb_servertester.MainActivity.addToDatabase(MainActivity.java:39)
                         at com.newhdc.pedergb.mongodb_servertester.MainActivity.access$000(MainActivity.java:14)
                         at com.newhdc.pedergb.mongodb_servertester.MainActivity$1.onClick(MainActivity.java:29)
                         at android.view.View.performClick(View.java:5637)
                         at android.view.View$PerformClick.run(View.java:22429)
                         at android.os.Handler.handleCallback(Handler.java:751)
                         at android.os.Handler.dispatchMessage(Handler.java:95)
                         at android.os.Looper.loop(Looper.java:154)
                         at android.app.ActivityThread.main(ActivityThread.java:6119)
                         at java.lang.reflect.Method.invoke(Native Method)
                         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
                         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
                      Caused by: java.lang.ClassNotFoundException: Didn't find class "java.lang.management.ManagementFactory" on path: DexPathList[[dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-support-annotations-25.1.0_11ac1b6ae4b8623fca16868c12f685674e962f99-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_9-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_8-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_7-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_6-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_5-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_4-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_3-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_2-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_1-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_0-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-mongodb-driver-core-3.4.2_cf1ecbf321a58b8bf97e118b2c0ff7614ac982a5-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-mongodb-driver-3.4.2_cfefe7ed281d321e57736b38e1e68fc6160680ac-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-com.android.support-support-vector-drawable-25.1.0_3dbe341ffa762dac2cc1137bc6aae1731f3bc1c0-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-com.android.support-support-v4-25.1.0_c534a46cb17b55c593319a94e0d90e0b75103a24-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-com.android.support-support-media-compat-25.1.0_b58e3876df91b49420cb0766dd6edfdbff0dedbc-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-com.android.support-support-fragment-25.1.0_d616629f11d994c207dfc4b5d01648e3194bccbc-classes.dex", dex f
I/cluster: Cluster created with settings {hosts=[ds123080.mlab.com:23080], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500}
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: **FATAL EXCEPTION**: main
                  Process: com.newhdc.pedergb.mongodb_servertester, PID: 4752
                  java.lang.ExceptionInInitializerError
                      at com.mongodb.connection.InternalStreamConnectionFactory.<init>(InternalStreamConnectionFactory.java:41)
                      at com.mongodb.connection.DefaultClusterableServerFactory.create(DefaultClusterableServerFactory.java:68)
                      at com.mongodb.connection.BaseCluster.createServer(BaseCluster.java:360)
                      at com.mongodb.connection.SingleServerCluster.<init>(SingleServerCluster.java:54)
                      at com.mongodb.connection.DefaultClusterFactory.create(DefaultClusterFactory.java:114)
                      at com.mongodb.Mongo.createCluster(Mongo.java:744)
                      at com.mongodb.Mongo.createCluster(Mongo.java:728)
                      at com.mongodb.Mongo.createCluster(Mongo.java:702)
                      at com.mongodb.Mongo.<init>(Mongo.java:310)
                      at com.mongodb.Mongo.<init>(Mongo.java:306)
                      at com.mongodb.MongoClient.<init>(MongoClient.java:284)
                      at com.newhdc.pedergb.mongodb_servertester.MainActivity.addToDatabase(MainActivity.java:39)
                      at com.newhdc.pedergb.mongodb_servertester.MainActivity.access$000(MainActivity.java:14)
                      at com.newhdc.pedergb.mongodb_servertester.MainActivity$1.onClick(MainActivity.java:29)
                      at android.view.View.performClick(View.java:5637)
                      at android.view.View$PerformClick.run(View.java:22429)
                      at android.os.Handler.handleCallback(Handler.java:751)
                      at android.os.Handler.dispatchMessage(Handler.java:95)
                      at android.os.Looper.loop(Looper.java:154)
                      at android.app.ActivityThread.main(ActivityThread.java:6119)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
                   Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.security.CodeSource java.security.ProtectionDomain.getCodeSource()' on a null object reference
                      at com.mongodb.connection.ClientMetadataHelper.getDriverVersion(ClientMetadataHelper.java:111)
                      at com.mongodb.connection.ClientMetadataHelper.getDriverInformation(ClientMetadataHelper.java:201)
                      at com.mongodb.connection.ClientMetadataHelper.addDriverInformation(ClientMetadataHelper.java:182)
                      at com.mongodb.connection.ClientMetadataHelper.<clinit>(ClientMetadataHelper.java:64)
                      at com.mongodb.connection.InternalStreamConnectionFactory.<init>(InternalStreamConnectionFactory.java:41)
                      at com.mongodb.connection.DefaultClusterableServerFactory.create(DefaultClusterableServerFactory.java:68)
                      at com.mongodb.connection.BaseCluster.createServer(BaseCluster.java:360)
                      at com.mongodb.connection.SingleServerCluster.<init>(SingleServerCluster.java:54)
                      at com.mongodb.connection.DefaultClusterFactory.create(DefaultClusterFactory.java:114)
                      at com.mongodb.Mongo.createCluster(Mongo.java:744)
                      at com.mongodb.Mongo.createCluster(Mongo.java:728)
                      at com.mongodb.Mongo.createCluster(Mongo.java:702)
                      at com.mongodb.Mongo.<init>(Mongo.java:310)
                      at com.mongodb.Mongo.<init>(Mongo.java:306)
                      at com.mongodb.MongoClient.<init>(MongoClient.java:284)
                      at com.newhdc.pedergb.mongodb_servertester.MainActivity.addToDatabase(MainActivity.java:39)
                      at com.newhdc.pedergb.mongodb_servertester.MainActivity.access$000(MainActivity.java:14)
                      at com.newhdc.pedergb.mongodb_servertester.MainActivity$1.onClick(MainActivity.java:29)
                      at android.view.View.performClick(View.java:5637)
                      at android.view.View$PerformClick.run(View.java:22429)
                      at android.os.Handler.handleCallback(Handler.java:751)
                      at android.os.Handler.dispatchMessage(Handler.java:95)
                      at android.os.Looper.loop(Looper.java:154)
                      at android.app.ActivityThread.main(ActivityThread.java:6119)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Application terminated.
</code>```

答:
Unfortunately, the Mongo Java Driver does not work on Android, as Android is missing some Java classes, according to this StackOverflow post. However, a kind StackOverflow user has forked the Mongo Java Driver and fixed the issue. You can see their version of the library on Github.

Scroll down to the description and download the latest jar file. Right now, it's this one:

https://github.com/matfur92/mongo-java-driver/blob/gh-pages/JARs/mongo-java-driver-3.4.0-SNAPSHOT.jar?raw=true.

Next, go ahead and delete the line in your build.gradle dependencies for mongo-java-driver. The line to delete should look something like this:

```<code>dependencies {
    ...
    compile 'org.mongodb:mongodb-driver:3.4.2'
    ...
}
</code>```

Finally, add the jar you downloaded to your application (guide here). Now your code should work without modification. I was able to use regular MongoDB functionality just fine, but I was not able to get GridFS to work.

ContentLicense: CC BY-SA 4.0

Body:
There's a lot of posts about this problem, but noone seems to work, so maby some things have changed.

I am trying to connect my android application to a MongoDB server located on mLab. I'm using Mongo Java Drived and have off course added the library to android studio.

It is possible to start the app, but when I click on the register button the application craches.

Here's my code:

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import org.bson.Document;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final EditText username = (EditText)findViewById(R.id.username);
    final Button bRegister = (Button) findViewById(R.id.bRegister);

    bRegister.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            String stringUsername = username.toString();
            try {
                addToDatabase(stringUsername);
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    });
}

private static void addToDatabase(String username){
    MongoClientURI uri  = new MongoClientURI("mongodb:///*mLab database URL */");
    MongoClient client = new MongoClient(uri);
    MongoDatabase db = client.getDatabase(uri.getDatabase());
    MongoCollection<Document> coll = db.getCollection("newDB");

    Document doc = new Document("username", username);
    coll.insertOne(doc);
    client.close();
}
}

I also have permision.INTERNET in the manifest file.

Any help would be very appreciated!

//Edit
Stacktrace:

03/10 02:43:09: Launching app
Cold swapped changes.
$ adb shell am start -n "com.newhdc.pedergb.mongodb_servertester/com.newhdc.pedergb.mongodb_servertester.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Client not ready yet..Waiting for process to come online
Connected to process 4752 on device emulator-5554
D/NetworkSecurityConfig: No Network Security Config specified, using platform default
W/org.bson.ObjectId: Failed to get process identifier from JMX, using random number instead
                     java.lang.NoClassDefFoundError: Failed resolution of: Ljava/lang/management/ManagementFactory;
                         at org.bson.types.ObjectId.createProcessIdentifier(ObjectId.java:533)
                         at org.bson.types.ObjectId.<clinit>(ObjectId.java:491)
                         at com.mongodb.connection.ClusterId.<init>(ClusterId.java:47)
                         at com.mongodb.connection.DefaultClusterFactory.create(DefaultClusterFactory.java:105)
                         at com.mongodb.Mongo.createCluster(Mongo.java:744)
                         at com.mongodb.Mongo.createCluster(Mongo.java:728)
                         at com.mongodb.Mongo.createCluster(Mongo.java:702)
                         at com.mongodb.Mongo.<init>(Mongo.java:310)
                         at com.mongodb.Mongo.<init>(Mongo.java:306)
                         at com.mongodb.MongoClient.<init>(MongoClient.java:284)
                         at com.newhdc.pedergb.mongodb_servertester.MainActivity.addToDatabase(MainActivity.java:39)
                         at com.newhdc.pedergb.mongodb_servertester.MainActivity.access$000(MainActivity.java:14)
                         at com.newhdc.pedergb.mongodb_servertester.MainActivity$1.onClick(MainActivity.java:29)
                         at android.view.View.performClick(View.java:5637)
                         at android.view.View$PerformClick.run(View.java:22429)
                         at android.os.Handler.handleCallback(Handler.java:751)
                         at android.os.Handler.dispatchMessage(Handler.java:95)
                         at android.os.Looper.loop(Looper.java:154)
                         at android.app.ActivityThread.main(ActivityThread.java:6119)
                         at java.lang.reflect.Method.invoke(Native Method)
                         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
                         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
                      Caused by: java.lang.ClassNotFoundException: Didn't find class "java.lang.management.ManagementFactory" on path: DexPathList[[dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-support-annotations-25.1.0_11ac1b6ae4b8623fca16868c12f685674e962f99-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_9-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_8-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_7-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_6-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_5-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_4-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_3-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_2-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_1-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-slice_0-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-mongodb-driver-core-3.4.2_cf1ecbf321a58b8bf97e118b2c0ff7614ac982a5-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-mongodb-driver-3.4.2_cfefe7ed281d321e57736b38e1e68fc6160680ac-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-com.android.support-support-vector-drawable-25.1.0_3dbe341ffa762dac2cc1137bc6aae1731f3bc1c0-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-com.android.support-support-v4-25.1.0_c534a46cb17b55c593319a94e0d90e0b75103a24-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-com.android.support-support-media-compat-25.1.0_b58e3876df91b49420cb0766dd6edfdbff0dedbc-classes.dex", dex file "/data/data/com.newhdc.pedergb.mongodb_servertester/files/instant-run/dex/slice-com.android.support-support-fragment-25.1.0_d616629f11d994c207dfc4b5d01648e3194bccbc-classes.dex", dex f
I/cluster: Cluster created with settings {hosts=[ds123080.mlab.com:23080], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500}
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: **FATAL EXCEPTION**: main
                  Process: com.newhdc.pedergb.mongodb_servertester, PID: 4752
                  java.lang.ExceptionInInitializerError
                      at com.mongodb.connection.InternalStreamConnectionFactory.<init>(InternalStreamConnectionFactory.java:41)
                      at com.mongodb.connection.DefaultClusterableServerFactory.create(DefaultClusterableServerFactory.java:68)
                      at com.mongodb.connection.BaseCluster.createServer(BaseCluster.java:360)
                      at com.mongodb.connection.SingleServerCluster.<init>(SingleServerCluster.java:54)
                      at com.mongodb.connection.DefaultClusterFactory.create(DefaultClusterFactory.java:114)
                      at com.mongodb.Mongo.createCluster(Mongo.java:744)
                      at com.mongodb.Mongo.createCluster(Mongo.java:728)
                      at com.mongodb.Mongo.createCluster(Mongo.java:702)
                      at com.mongodb.Mongo.<init>(Mongo.java:310)
                      at com.mongodb.Mongo.<init>(Mongo.java:306)
                      at com.mongodb.MongoClient.<init>(MongoClient.java:284)
                      at com.newhdc.pedergb.mongodb_servertester.MainActivity.addToDatabase(MainActivity.java:39)
                      at com.newhdc.pedergb.mongodb_servertester.MainActivity.access$000(MainActivity.java:14)
                      at com.newhdc.pedergb.mongodb_servertester.MainActivity$1.onClick(MainActivity.java:29)
                      at android.view.View.performClick(View.java:5637)
                      at android.view.View$PerformClick.run(View.java:22429)
                      at android.os.Handler.handleCallback(Handler.java:751)
                      at android.os.Handler.dispatchMessage(Handler.java:95)
                      at android.os.Looper.loop(Looper.java:154)
                      at android.app.ActivityThread.main(ActivityThread.java:6119)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
                   Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.security.CodeSource java.security.ProtectionDomain.getCodeSource()' on a null object reference
                      at com.mongodb.connection.ClientMetadataHelper.getDriverVersion(ClientMetadataHelper.java:111)
                      at com.mongodb.connection.ClientMetadataHelper.getDriverInformation(ClientMetadataHelper.java:201)
                      at com.mongodb.connection.ClientMetadataHelper.addDriverInformation(ClientMetadataHelper.java:182)
                      at com.mongodb.connection.ClientMetadataHelper.<clinit>(ClientMetadataHelper.java:64)
                      at com.mongodb.connection.InternalStreamConnectionFactory.<init>(InternalStreamConnectionFactory.java:41)
                      at com.mongodb.connection.DefaultClusterableServerFactory.create(DefaultClusterableServerFactory.java:68)
                      at com.mongodb.connection.BaseCluster.createServer(BaseCluster.java:360)
                      at com.mongodb.connection.SingleServerCluster.<init>(SingleServerCluster.java:54)
                      at com.mongodb.connection.DefaultClusterFactory.create(DefaultClusterFactory.java:114)
                      at com.mongodb.Mongo.createCluster(Mongo.java:744)
                      at com.mongodb.Mongo.createCluster(Mongo.java:728)
                      at com.mongodb.Mongo.createCluster(Mongo.java:702)
                      at com.mongodb.Mongo.<init>(Mongo.java:310)
                      at com.mongodb.Mongo.<init>(Mongo.java:306)
                      at com.mongodb.MongoClient.<init>(MongoClient.java:284)
                      at com.newhdc.pedergb.mongodb_servertester.MainActivity.addToDatabase(MainActivity.java:39)
                      at com.newhdc.pedergb.mongodb_servertester.MainActivity.access$000(MainActivity.java:14)
                      at com.newhdc.pedergb.mongodb_servertester.MainActivity$1.onClick(MainActivity.java:29)
                      at android.view.View.performClick(View.java:5637)
                      at android.view.View$PerformClick.run(View.java:22429)
                      at android.os.Handler.handleCallback(Handler.java:751)
                      at android.os.Handler.dispatchMessage(Handler.java:95)
                      at android.os.Looper.loop(Looper.java:154)
                      at android.app.ActivityThread.main(ActivityThread.java:6119)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Application terminated.

Body:
Unfortunately, the Mongo Java Driver does not work on Android, as Android is missing some Java classes, according to this StackOverflow post. However, a kind StackOverflow user has forked the Mongo Java Driver and fixed the issue. You can see their version of the library on Github.

Scroll down to the description and download the latest jar file. Right now, it's this one:

https://github.com/matfur92/mongo-java-driver/blob/gh-pages/JARs/mongo-java-driver-3.4.0-SNAPSHOT.jar?raw=true.

Next, go ahead and delete the line in your build.gradle dependencies for mongo-java-driver. The line to delete should look something like this:

dependencies {
    ...
    compile 'org.mongodb:mongodb-driver:3.4.2'
    ...
}

Finally, add the jar you downloaded to your application (guide here). Now your code should work without modification. I was able to use regular MongoDB functionality just fine, but I was not able to get GridFS to work.


问:
Convert all letters from uppercase to lowercase in a sentence except words with all CAPS using R
I want to convert my data frame of text into lowercase but I do not want to convert the words with all CAPS letters. For example if have a string like

"My friEnd ENRIQUE is nOt GOoD in stuDies"

The output of this should be like

"my friend ENRIQUE is not good in studies"

It converted everything to lowercase except words with all capital letters.
I need a r function to do this task.

答:
You can do this with gsub and a (perl compatible) regular expression.

```<code>gsub("(\\b\\w*[a-z]\\w*\\b)", "\\L\\1", String, perl=TRUE)
"my friend ENRIQUE is not good in studies"
</code>```

Putting \\b word boundaries insures that this operates on separate words.  [a-z] picks the words that contain at least one lower case letter. The \\w* before and after [a-z] matches any number (including zero) of "word characters" i.e. letters or numbers.  The \\L in the substitution pattern converts to lower case.

Body:
You can do this with gsub and a (perl compatible) regular expression.

gsub("(\\b\\w*[a-z]\\w*\\b)", "\\L\\1", String, perl=TRUE)
"my friend ENRIQUE is not good in studies"

Putting \\b word boundaries insures that this operates on separate words.  [a-z] picks the words that contain at least one lower case letter. The \\w* before and after [a-z] matches any number (including zero) of "word characters" i.e. letters or numbers.  The \\L in the substitution pattern converts to lower case.


问:
How to unscope the default scope for the specific model in the whole rails active record association chain?
I'm trying to solve the following problem. I have three models: User has_many Camera has_many Recordings.

```<code>class AddTables < ActiveRecord::Migration
  def change
    create_table :users
    create_table :cameras do |t|
      t.references :user, null: false, foreign_key: true
      t.timestamp :archived_at, index: true
    end
    create_table :recordings do |t|
      t.references :camera, null: false, foreign_key: true
      t.timestamp :archived_at, index: true
    end
  end
end
</code>```

Camera and Recording have the special field "archived_at" to mark a record as deleted (soft delete). I want User#recordings to look through all the cameras (any Camera.archived_at), but, at the same time, I want it to look through only not arcvhied Recordings (Recording.archived_at == nil). I've tried several cases, but have got no success.

=== CASE 1 ===

```<code>class User < ActiveRecord::Base
  has_many :cameras, -> { unscope where: :archived_at }
  has_many :recordings, through: :cameras
end

class Camera < ActiveRecord::Base
  default_scope { where(archived_at: nil) }

  belongs_to :user
  has_many :recordings
end

class Recording < ActiveRecord::Base
  default_scope { where(archived_at: nil) }

  belongs_to :camera
end
</code>```

irb(main):013:0> reload!; User.first.recordings(true)
Reloading...
  User Load (0.1ms)  SELECT  "users".* FROM "users"  ORDER BY "users"."id" ASC LIMIT 1
  Recording Load (0.2ms)  SELECT "recordings".* FROM "recordings" INNER JOIN "cameras" ON "recordings"."camera_id" = "cameras"."id" WHERE "cameras"."user_id" = $1  [["user_id", 1]]
=> #]>

=== CASE 2 ===

```<code>class User < ActiveRecord::Base
  has_many :cameras, -> { unscope where: :archived_at }
  has_many :recordings, through: :cameras
end

class Camera < ActiveRecord::Base
  default_scope { where(cameras: {archived_at: nil}) }

  belongs_to :user
  has_many :recordings
end

class Recording < ActiveRecord::Base
  default_scope { where(recordings: {archived_at: nil}) }

  belongs_to :camera
end
</code>```

irb(main):013:0> reload!; User.first.recordings(true)
Reloading...
  User Load (0.1ms)  SELECT  "users".* FROM "users"  ORDER BY "users"."id" ASC LIMIT 1
  Recording Load (0.2ms)  SELECT "recordings".* FROM "recordings" INNER JOIN "cameras" ON "recordings"."camera_id" = "cameras"."id" WHERE "cameras"."user_id" = $1  [["user_id", 1]]
=> #]>
irb(main):014:0> reload!; User.first.recordings(true)
Reloading...
  User Load (0.1ms)  SELECT  "users".* FROM "users"  ORDER BY "users"."id" ASC LIMIT 1
  Recording Load (0.2ms)  SELECT "recordings".* FROM "recordings" INNER JOIN "cameras" ON "recordings"."camera_id" = "cameras"."id" WHERE "recordings"."archived_at" IS NULL AND "cameras"."archived_at" IS NULL AND "cameras"."user_id" = $1  [["user_id", 1]]
=> #]>

=== CASE 3 ===

```<code>class User < ActiveRecord::Base
  has_many :cameras, -> { unscope where: {cameras: :archived_at} }
  has_many :recordings, through: :cameras
end

class Camera < ActiveRecord::Base
  default_scope { where(cameras: {archived_at: nil}) }

  belongs_to :user
  has_many :recordings
end

class Recording < ActiveRecord::Base
  default_scope { where(recordings: {archived_at: nil}) }

  belongs_to :camera
end
</code>```

irb(main):016:0> reload!; User.first.recordings(true)
Reloading...
  User Load (0.2ms)  SELECT  "users".* FROM "users"  ORDER BY "users"."id" ASC LIMIT 1
  Recording Load (0.2ms)  SELECT "recordings".* FROM "recordings" INNER JOIN "cameras" ON "recordings"."camera_id" = "cameras"."id" WHERE "recordings"."archived_at" IS NULL AND "cameras"."archived_at" IS NULL AND "cameras"."user_id" = $1  [["user_id", 1]]
=> #]>

答:
Try this out:

user.rb:

```<code>class User < ApplicationRecord
    has_many :cameras
    has_many :recordings, -> { unscope(where: :archived_at).where(recordings: {archived_at: nil}) }, through: :cameras
end
</code>```

camera.rb:

```<code>class Camera < ApplicationRecord
    default_scope { where(archived_at: nil) }
    belongs_to :user
    has_many :recordings
end
</code>```

recording.rb:

```<code>class Recording < ApplicationRecord
    belongs_to :camera
    default_scope { where(archived_at: nil) }
end
</code>```

Here's the output query:

```<code>irb(main):088:0> User.first.recordings
User Load (0.2ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
Recording Load (0.1ms)  SELECT "recordings".* FROM "recordings" INNER JOIN "cameras" ON "recordings"."camera_id" = "cameras"."id" WHERE "cameras"."user_id" = ? AND "recordings"."archived_at" IS NULL  [["user_id", 1]]
</code>```

Body:
I'm trying to solve the following problem. I have three models: User has_many Camera has_many Recordings.

class AddTables < ActiveRecord::Migration
  def change
    create_table :users
    create_table :cameras do |t|
      t.references :user, null: false, foreign_key: true
      t.timestamp :archived_at, index: true
    end
    create_table :recordings do |t|
      t.references :camera, null: false, foreign_key: true
      t.timestamp :archived_at, index: true
    end
  end
end

Camera and Recording have the special field "archived_at" to mark a record as deleted (soft delete). I want User#recordings to look through all the cameras (any Camera.archived_at), but, at the same time, I want it to look through only not arcvhied Recordings (Recording.archived_at == nil). I've tried several cases, but have got no success.

=== CASE 1 ===

class User < ActiveRecord::Base
  has_many :cameras, -> { unscope where: :archived_at }
  has_many :recordings, through: :cameras
end

class Camera < ActiveRecord::Base
  default_scope { where(archived_at: nil) }

  belongs_to :user
  has_many :recordings
end

class Recording < ActiveRecord::Base
  default_scope { where(archived_at: nil) }

  belongs_to :camera
end

irb(main):013:0> reload!; User.first.recordings(true)
Reloading...
  User Load (0.1ms)  SELECT  "users".* FROM "users"  ORDER BY "users"."id" ASC LIMIT 1
  Recording Load (0.2ms)  SELECT "recordings".* FROM "recordings" INNER JOIN "cameras" ON "recordings"."camera_id" = "cameras"."id" WHERE "cameras"."user_id" = $1  [["user_id", 1]]
=> #]>

=== CASE 2 ===

class User < ActiveRecord::Base
  has_many :cameras, -> { unscope where: :archived_at }
  has_many :recordings, through: :cameras
end

class Camera < ActiveRecord::Base
  default_scope { where(cameras: {archived_at: nil}) }

  belongs_to :user
  has_many :recordings
end

class Recording < ActiveRecord::Base
  default_scope { where(recordings: {archived_at: nil}) }

  belongs_to :camera
end

irb(main):013:0> reload!; User.first.recordings(true)
Reloading...
  User Load (0.1ms)  SELECT  "users".* FROM "users"  ORDER BY "users"."id" ASC LIMIT 1
  Recording Load (0.2ms)  SELECT "recordings".* FROM "recordings" INNER JOIN "cameras" ON "recordings"."camera_id" = "cameras"."id" WHERE "cameras"."user_id" = $1  [["user_id", 1]]
=> #]>
irb(main):014:0> reload!; User.first.recordings(true)
Reloading...
  User Load (0.1ms)  SELECT  "users".* FROM "users"  ORDER BY "users"."id" ASC LIMIT 1
  Recording Load (0.2ms)  SELECT "recordings".* FROM "recordings" INNER JOIN "cameras" ON "recordings"."camera_id" = "cameras"."id" WHERE "recordings"."archived_at" IS NULL AND "cameras"."archived_at" IS NULL AND "cameras"."user_id" = $1  [["user_id", 1]]
=> #]>

=== CASE 3 ===

class User < ActiveRecord::Base
  has_many :cameras, -> { unscope where: {cameras: :archived_at} }
  has_many :recordings, through: :cameras
end

class Camera < ActiveRecord::Base
  default_scope { where(cameras: {archived_at: nil}) }

  belongs_to :user
  has_many :recordings
end

class Recording < ActiveRecord::Base
  default_scope { where(recordings: {archived_at: nil}) }

  belongs_to :camera
end

irb(main):016:0> reload!; User.first.recordings(true)
Reloading...
  User Load (0.2ms)  SELECT  "users".* FROM "users"  ORDER BY "users"."id" ASC LIMIT 1
  Recording Load (0.2ms)  SELECT "recordings".* FROM "recordings" INNER JOIN "cameras" ON "recordings"."camera_id" = "cameras"."id" WHERE "recordings"."archived_at" IS NULL AND "cameras"."archived_at" IS NULL AND "cameras"."user_id" = $1  [["user_id", 1]]
=> #]>

Body:
Try this out:

user.rb:

class User < ApplicationRecord
    has_many :cameras
    has_many :recordings, -> { unscope(where: :archived_at).where(recordings: {archived_at: nil}) }, through: :cameras
end

camera.rb:

class Camera < ApplicationRecord
    default_scope { where(archived_at: nil) }
    belongs_to :user
    has_many :recordings
end

recording.rb:

class Recording < ApplicationRecord
    belongs_to :camera
    default_scope { where(archived_at: nil) }
end

Here's the output query:

irb(main):088:0> User.first.recordings
User Load (0.2ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
Recording Load (0.1ms)  SELECT "recordings".* FROM "recordings" INNER JOIN "cameras" ON "recordings"."camera_id" = "cameras"."id" WHERE "cameras"."user_id" = ? AND "recordings"."archived_at" IS NULL  [["user_id", 1]]