How to synchronize time with Firebase server in Java client? - java

I need to synchronize the time on a Java client application with the Firebase server, to prevent fails when the client system time is different from the server. Is it possible?
Here's my Firebase class code that starts the application:
private static FirebaseOptions getOptions() throws Exception {
/* ... */
for (Map<String, FirebaseOptions> map : credentials) {
if (map.containsKey(uri)) {
return map.get(uri);
}
}
try {
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(getCredentials(uri))
.build();
/* ... */
return options;
} catch (Exception e) {
/* ... */
}
}
public Firebase(String projectId) {
try {
try {
app = FirebaseApp.getInstance(projectId);
} catch (IllegalStateException e) {
FirebaseOptions options = getOptions();
for (FirebaseApp fapp : apps) {
if (fapp.getOptions().equals(options)) {
app = fapp;
}
}
if (app == null) {
app = FirebaseApp.initializeApp(options, projectId);
apps.add(app);
}
}
} catch (Exception e) {
error = e;
}
}
I can request the server timestamp by HTTP request, but how to change the time in the Java client? I tried use the FirestoreOptions setClock, but it still uses the system time, and works only if the system time is ok:
ZonedDateTime server = getServerTime();
ZonedDateTime now = ZonedDateTime.now();
long offsetNano = server.getNano() - now.getNano();
long offsetMilli = server.toInstant().toEpochMilli() - now.toInstant().toEpochMilli();
try {
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(getCredentials(uri))
.setFirestoreOptions(
FirestoreOptions
.newBuilder()
.setClock(new ApiClock() {
#Override
public long nanoTime() {
return ZonedDateTime.now().getNano() + offsetNano;
}
#Override
public long millisTime() {
return ZonedDateTime.now().toInstant().toEpochMilli() + offsetMilli;
}
})
.build()
)
.build();

Related

Vert.x Web , GraphQL , Hibernate Reactive

I am going to write an Api with Vert.x web and GraphQL
I have connected with the database with Hibernate reactive
public void start(final Promise<Void> startPromise)
{
try
{
vertx.executeBlocking(e ->
{
try
{
hibernateConfig();
e.complete();
}
catch (Exception exception)
{
e.fail(exception.getCause());
}
}).onComplete(event ->
{
try
{
runServer(startPromise);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}).onFailure(Throwable::printStackTrace);
}
catch (Exception e)
{
e.printStackTrace();
}
}
private void runServer(final Promise<Void> startPromise) throws Exception
{
final HttpServer httpServer = vertx.createHttpServer();
final Router router = Router.router(vertx);
router.route().handler(BodyHandler.create());
router.post("/graphql").handler(super::graphqlHandler);
// register `/graphiql` endpoint for the GraphiQL UI
final GraphiQLHandlerOptions graphiqlOptions = new GraphiQLHandlerOptions().setEnabled(true);
router.route("/graphiql/*").handler(GraphiQLHandler.create(graphiqlOptions));
final URL resource = getClass().getResource("/static");
if (resource != null) router.route("/static/*").handler(StaticHandler.create(resource.getFile()));
else throw new Exception("Cannot set static");
httpServer.requestHandler(router).listen(PORT , "localhost" , event ->
{
if (event.succeeded())
{
System.out.printf("Server run on port %d!\n" , PORT);
startPromise.complete();
}
else
{
System.out.println("Error run server!");
startPromise.fail(event.cause());
}
});
}
private void hibernateConfig()
{
Uni.createFrom().deferred(Unchecked.supplier(() ->
{
final Configuration configuration = new Configuration().setProperties(getHibernateProperties());
final Set<Class<?>> entitiesClasses = getEntitiesClasses();
if (entitiesClasses != null)
{
for (final Class<?> entity : entitiesClasses) configuration.addAnnotatedClass(entity);
}
else logger.error("Cannot found entities");
final StandardServiceRegistryBuilder builder = new ReactiveServiceRegistryBuilder()
.addService(Server.class , this)
.applySettings(configuration.getProperties());
final StandardServiceRegistry registry = builder.build();
sessionFactory = configuration.buildSessionFactory(registry).unwrap(Mutiny.SessionFactory.class);
if (!sessionFactory.isOpen()) throw new RuntimeException("Session is close!");
logger.info("✅ Hibernate Reactive is ready");
return Uni.createFrom().voidItem();
})).convert().toCompletableFuture().join();
}
private Properties getHibernateProperties()
{
final Properties properties = new Properties();
properties.setProperty(Environment.DRIVER , "org.mysql.jdbc.DRIVER");
properties.setProperty(Environment.URL , "jdbc:mysql://localhost:3306/DBNAME");
properties.setProperty(Environment.USER , "USENAME");
properties.setProperty(Environment.PASS , "PASSWORD");
properties.setProperty(Environment.DIALECT , "org.hibernate.dialect.MySQL55Dialect");
properties.setProperty(Environment.HBM2DDL_DATABASE_ACTION , "create");
properties.setProperty(Environment.SHOW_SQL , "false");
properties.setProperty(Environment.POOL_SIZE , "10");
return properties;
}
So far it doesn't give any error and creates the entities
The error is given when I want to do an Insert
public Future<UsersDto> addUserTest(final DataFetchingEnvironment environment)
{
return Future.future(event ->
{
final AddUsersDto addUsersDto = Dto.mapped(environment.getArguments() , "user" , AddUsersDto.class);
final Users user = UsersMapper.toUsers(addUsersDto);
try
{
vertx.executeBlocking(e ->
{
try
{
sessionFactory.withTransaction(
(session , transaction) ->
session.persist(user)
.chain(session::flush)
)
.invoke(() -> e.complete(user))
.onFailure()
.invoke(e::fail)
.await()
.indefinitely();
}
catch (Exception exception)
{
exception.printStackTrace();
e.fail(exception.getCause());
}
})
.onComplete(e -> event.complete(UsersMapper.toUsersDto((Users) e.result())))
.onFailure(e -> event.fail(e.getCause()));
}
catch (Exception e)
{
e.printStackTrace();
event.complete(UsersDto.builder().build());
}
});
}
Error:
sessionFactory.withTransaction(
(session , transaction) ->
session.persist(user)
.chain(session::flush)
)
.invoke(() -> e.complete(user))
.onFailure()
.invoke(e::fail)
.await()
.indefinitely(); // This line gives an error
Error text:
java.lang.IllegalStateException: HR000068: This method should exclusively be invoked from a Vert.x EventLoop thread; currently running on thread 'vert.x-worker-thread-1'
Please help me if anyone knows the problem
The problem is that you are running everything in the worker thread (using executeBlocking).
If you are writing reactive code, you don't need to wait for the result to be available.
The code should look something like this:
public Future<UsersDto> addUserTest(final DataFetchingEnvironment environment) {
return Future.future(event -> {
final AddUsersDto addUsersDto = Dto.mapped(environment.getArguments() , "user" , AddUsersDto.class);
final Users user = UsersMapper.toUsers(addUsersDto);
sessionFactory
.withTransaction( (session , tx) -> session.persist(user) )
.subscribe().with( event::complete, event::fail )
});
}
You also don't need to flush because there's a transaction.
There is a working example on the Hibernate Reactive repository

Use TransferManager to upload directory to s3 in Java failed without exception

I am using TransferManager to upload a directory (including large number of files 10k ~ 100k count) to s3 and I found that sometimes the upload maybe failed or stuck without any exception or success handler. The log just show that it started to upload to s3 but it never show it finished or failed.
I show my code below, hope someone can help me figure out what is going wrong.
#PostMapping
public ResponseEntity upload(
#RequestPart("file") #Valid
MultipartFile file) throws IOException {
try {
File dest = File.createTempFile(UUID.randomUUID().toString(), "zip");
if (!dest.getParentFile().exists()) {
Files.createDirectories(dest.getParentFile().toPath());
}
file.transferTo(dest);
CompletableFuture.supplyAsync(() -> {
try {
long size = fileUploadService
.upload(new FileInputStream(dest),uploadDescriptor.getTargetPath());
if (size <= 0) {
log.fail();
} else {
log.success();
}
} catch (FileNotFoundException e) {
log.fail();
log.error(e.getMessage());
e.printStackTrace();
}
return dest.delete();
}, executor);
} catch (IOException e) {
log.error(e.getMessage());
e.printStackTrace();
}
return ResponseEntity.accepted().build();
}
And here is the FileUploadService:
public class FileUploadService {
private StorageService storageService;
#Autowired
public FileUploadService(StorageService storageService) {
this.storageService = storageService;
}
public long upload(InputStream inputStream, String path) {
try {
Path tempDirectory = Files.createTempDirectory(UUID.randomUUID().toString());
unzip(inputStream, tempDirectory);
long size = FileUtils.sizeOfDirectory(tempDirectory.toFile());
boolean isSuccess = storageService.storeDir(tempDirectory.toFile(), path);
FileSystemUtils.deleteRecursively(tempDirectory);
return isSuccess ? size : -1;
} catch (IOException e) {
e.printStackTrace();
log.error("failed to update to {}", path);
log.error(e.getMessage());
return -1;
}
}
}
Here is the StorageService:
#Slf4j
public class StorageService {
private static final String SUFFIX = "/";
private S3Configuration configuration;
private final AmazonS3 s3Client;
#Autowired
public S3StorageService(S3Configuration configuration) {
this.configuration = configuration;
BasicAWSCredentials awsCreds = new BasicAWSCredentials(
configuration.getAccessKey(), configuration.getAccessSecret());
s3Client = AmazonS3ClientBuilder.standard()
.withRegion(configuration.getRegion())
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.build();
}
#Override
public boolean storeDir(File file, String fullPath) {
log.info("start upload from {} to {}", file.toString(), fullPath);
TransferManager manager = TransferManagerBuilder.standard().withS3Client(s3Client).build();
try {
MultipleFileUpload xfer = manager.uploadDirectory(configuration.getBucketName(),
fullPath, file, true);
xfer.waitForCompletion();
log.info("finish upload from {} to {}", file.toString(), fullPath);
return true;
} catch (AmazonServiceException | InterruptedException e) {
e.printStackTrace();
log.error("failed to update from {} to {}", file.toString(), fullPath);
log.error(e.getMessage());
return false;
} finally {
manager.shutdownNow(false);
}
}
}
Why don't you rather try "waitForException"? Or better still monitor the progress so you can see how far it gets and check for errors/completion at the end, and when it does finish, check the state for errors etc.

OPC Client for milo fails to connect to local OPC discovery service

I am new to OPC UA and I am using milo OPC Subscriber client to connect to local discovery service. I have Prosys simulation server which is connected to my local discovery service.
Note: If I connect directly to prosys endpoint it works fine. It fails only through discovery service.
I get the following exception when I run my code
<pre>12:38:35.916 [main] INFO org.eclipse.milo.opcua.stack.core.Stack -
Successfully removed cryptography restrictions. 12:38:36.167 [main]
INFO com.company.OpcuaClientRunner - security temp dir:
C:\Users\Z003Z2YP\AppData\Local\Temp\security 12:38:36.173 [main] INFO
com.company.KeyStoreLoader - Loading KeyStore at
C:\Users\Z003Z2YP\AppData\Local\Temp\security\example-client.pfx
12:38:37.594 [main] INFO com.company.OpcuaClientRunner - Using
endpoint: opc.tcp://<hostname>:4840 [None] 12:38:37.600 [main] INFO
org.eclipse.milo.opcua.sdk.client.OpcUaClient - Eclipse Milo OPC UA
Stack version: 0.2.3 12:38:37.600 [main] INFO
org.eclipse.milo.opcua.sdk.client.OpcUaClient - Eclipse Milo OPC UA
Client SDK version: 0.2.3 12:38:37.809 [NonceUtilSecureRandom] INFO
org.eclipse.milo.opcua.stack.core.util.NonceUtil - SecureRandom seeded
in 0ms. 12:38:37.815 [ua-netty-event-loop-1] ERROR
org.eclipse.milo.opcua.stack.client.handlers.UaTcpClientMessageHandler
- [remote=<hostname>/<IP>:4840] errorMessage=ErrorMessage{error=StatusCode{name=Bad_ServiceUnsupported,
value=0x800B0000, quality=bad}, reason=null} 12:38:53.828 [main] ERROR
com.company.OpcuaClientRunner - Error running client example:
UaException: status=Bad_Timeout, message=request timed out after
16000ms java.util.concurrent.ExecutionException: UaException:
status=Bad_Timeout, message=request timed out after 16000ms
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
at com.company.OpcuaSubscriber.run(OpcuaSubscriber.java:49)
at com.company.OpcuaClientRunner.run(OpcuaClientRunner.java:122)
at com.company.OpcuaSubscriber.main(OpcuaSubscriber.java:120) Caused by:
org.eclipse.milo.opcua.stack.core.UaException: request timed out after
16000ms
at org.eclipse.milo.opcua.stack.client.UaTcpStackClient.lambda$scheduleRequestTimeout$13(UaTcpStackClient.java:326)
at io.netty.util.HashedWheelTimer$HashedWheelTimeout.expire(HashedWheelTimer.java:581)
at io.netty.util.HashedWheelTimer$HashedWheelBucket.expireTimeouts(HashedWheelTimer.java:655)
at io.netty.util.HashedWheelTimer$Worker.run(HashedWheelTimer.java:367)
at java.lang.Thread.run(Thread.java:748) 12:38:53.828 [main] ERROR
com.company.OpcuaClientRunner - Error running example: UaException:
status=Bad_Timeout, message=request timed out after 16000ms
java.util.concurrent.ExecutionException: UaException:
status=Bad_Timeout, message=request timed out after 16000ms
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
at com.company.OpcuaSubscriber.run(OpcuaSubscriber.java:49)
at com.company.OpcuaClientRunner.run(OpcuaClientRunner.java:122)
at com.company.OpcuaSubscriber.main(OpcuaSubscriber.java:120) Caused by:
org.eclipse.milo.opcua.stack.core.UaException: request timed out after
16000ms
at org.eclipse.milo.opcua.stack.client.UaTcpStackClient.lambda$scheduleRequestTimeout$13(UaTcpStackClient.java:326)
at io.netty.util.HashedWheelTimer$HashedWheelTimeout.expire(HashedWheelTimer.java:581)
at io.netty.util.HashedWheelTimer$HashedWheelBucket.expireTimeouts(HashedWheelTimer.java:655)
at io.netty.util.HashedWheelTimer$Worker.run(HashedWheelTimer.java:367)
at java.lang.Thread.run(Thread.java:748)</pre>
Code to create client in ClientRunner.
private OpcUaClient createClient() throws Exception {
File securityTempDir = new File(System.getProperty("java.io.tmpdir"), "security");
if (!securityTempDir.exists() && !securityTempDir.mkdirs()) {
throw new Exception("unable to create security dir: " + securityTempDir);
}
LoggerFactory.getLogger(getClass())
.info("security temp dir: {}", securityTempDir.getAbsolutePath());
KeyStoreLoader loader = new KeyStoreLoader().load(securityTempDir);
loader.load();
SecurityPolicy securityPolicy = client.getSecurityPolicy();
EndpointDescription[] endpoints;
try {
endpoints = UaTcpStackClient
.getEndpoints(client.getEndpointUrl())
.get();
} catch (Throwable ex) {
ex.printStackTrace();
// try the explicit discovery endpoint as well
String discoveryUrl = client.getEndpointUrl();
logger.info("Trying explicit discovery URL: {}", discoveryUrl);
endpoints = UaTcpStackClient
.getEndpoints(discoveryUrl)
.get();
}
EndpointDescription endpoint = Arrays.stream(endpoints)
.filter(e -> e.getSecurityPolicyUri().equals(securityPolicy.getSecurityPolicyUri()))
.findFirst().orElseThrow(() -> new Exception("no desired endpoints returned"));
logger.info("Using endpoint: {} [{}]", endpoint.getEndpointUrl(), securityPolicy);
OpcUaClientConfig config = OpcUaClientConfig.builder()
.setApplicationName(LocalizedText.english("eclipse milo opc-ua client"))
.setApplicationUri("urn:eclipse:milo:examples:client")
.setCertificate(loader.getClientCertificate())
.setKeyPair(loader.getClientKeyPair())
.setEndpoint(endpoint)
.setIdentityProvider(client.getIdentityProvider())
.setRequestTimeout(uint(5000))
.build();
return new OpcUaClient(config);
Client interface class
public interface OpcuaClientInterface {
public static final String USERNAME = "demo";
public static final String PASSWORD = "demo";
default String getEndpointUrl() {
return "opc.tcp://localhost:4840/UADiscovery";
}
default SecurityPolicy getSecurityPolicy() {
return SecurityPolicy.None;
}
default IdentityProvider getIdentityProvider() {
// return new UsernameProvider(USERNAME,PASSWORD);
return new AnonymousProvider();
}
void run (OpcUaClient client, CompletableFuture future) throws Exception;
}
subscriber run implementation
#Override
public void run(OpcUaClient client, CompletableFuture future) throws Exception {
// synchronous connect
client.connect().get();
// create a subscription # 1000ms
UaSubscription subscription = client.getSubscriptionManager().createSubscription(1000.0).get();
List nodeIds = Arrays.asList("SuctionPressure", "DischargePressure", "Flow", "BearingTemperature", "Vibration", "Power");
// List nodeIds = Arrays.asList("DS", "PV");
List MICRs = nodeIds.stream().map(id -> {
ReadValueId readValueId = new ReadValueId(new NodeId(3, id), AttributeId.Value.uid(), null,
QualifiedName.NULL_VALUE);
// important: client handle must be unique per item
UInteger clientHandle = uint(clientHandles.getAndIncrement());
MonitoringParameters parameters = new MonitoringParameters(clientHandle, 1000.0, // sampling interval
null, // filter, null means use default
uint(10), // queue size
true // discard oldest
);
MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(readValueId, MonitoringMode.Reporting,
parameters);
return request;
}).collect(Collectors.toList());
// when creating items in MonitoringMode.Reporting this callback is where each
// item needs to have its
// value/event consumer hooked up. The alternative is to create the item in
// sampling mode, hook up the
// consumer after the creation call completes, and then change the mode for all
// items to reporting.
BiConsumer onItemCreated = (item, id) -> item
.setValueConsumer(this::onSubscriptionValue);
List items = subscription.createMonitoredItems(TimestampsToReturn.Both, MICRs, onItemCreated)
.get();
for (UaMonitoredItem item : items) {
if (item.getStatusCode().isGood()) {
logger.info("item created for nodeId={}", item.getReadValueId().getNodeId());
} else {
logger.warn("failed to create item for nodeId={} (status={})", item.getReadValueId().getNodeId(),
item.getStatusCode());
}
}
// let the example run for 5 seconds then terminate
// Thread.sleep(1000 * 60 * 1);
// future.complete(client);
}
I got it working with the milo OPC Subscriber client.
following is the changes I did in the classes.
Client Interface
public interface OpcuaClientInterface {
public static final String USERNAME = "demo";
public static final String PASSWORD = "demo";
public static final String UaServerName = "SimulationServer";
default String getEndpointUrl() {
return "opc.tcp://localhost:4840";
}
default SecurityPolicy getSecurityPolicy() {
return SecurityPolicy.None;
}
default String getUaServerName () {
return UaServerName;
}
default IdentityProvider getIdentityProvider() {
return new UsernameProvider(USERNAME,PASSWORD);
}
void run (OpcUaClient client, CompletableFuture<OpcUaClient> future) throws Exception;
}
client runner class
public class OpcuaClientRunner {
static {
CryptoRestrictions.remove();
Security.addProvider(new BouncyCastleProvider());
}
private final AtomicLong requestHandle = new AtomicLong(1L);
private final Logger logger = LoggerFactory.getLogger(getClass());
private final CompletableFuture<OpcUaClient> future = new CompletableFuture<>();
private final OpcuaClientInterface client;
public OpcuaClientRunner(OpcuaClientInterface client) throws Exception {
this.client = client;
}
private KeyStoreLoader createKeyStore() {
KeyStoreLoader loader = null;
try {
File securityTempDir = new File(System.getProperty("java.io.tmpdir"), "security");
if (!securityTempDir.exists() && !securityTempDir.mkdirs()) {
throw new Exception("unable to create security dir: " + securityTempDir);
}
LoggerFactory.getLogger(getClass()).info("security temp dir: {}", securityTempDir.getAbsolutePath());
loader = new KeyStoreLoader().load(securityTempDir);
loader.load();
} catch (Exception e) {
logger.error("Could not load keys {}", e);
return null;
}
return loader;
}
private CompletableFuture<ServerOnNetwork[]> findServersOnNetwork(String discoveryEndpointUrl)
throws InterruptedException, ExecutionException {
UaStackClient c = createDiscoveryClient(client.getEndpointUrl()).connect().get();
RequestHeader header = new RequestHeader(NodeId.NULL_VALUE, DateTime.now(),
uint(requestHandle.getAndIncrement()), uint(0), null, uint(60), null);
FindServersOnNetworkRequest request = new FindServersOnNetworkRequest(header, null, null, null);
return c.<FindServersOnNetworkResponse>sendRequest(request).thenCompose(result -> {
StatusCode statusCode = result.getResponseHeader().getServiceResult();
if (statusCode.isGood()) {
return CompletableFuture.completedFuture(result.getServers());
} else {
CompletableFuture<ServerOnNetwork[]> f = new CompletableFuture<>();
f.completeExceptionally(new UaException(statusCode));
return f;
}
});
}
private UaTcpStackClient createDiscoveryClient(String endpointUrl) {
KeyStoreLoader loader = createKeyStore();
if (loader == null) {
return null;
}
UaTcpStackClientConfig config = UaTcpStackClientConfig.builder()
.setApplicationName(LocalizedText.english("Stack Example Client"))
.setApplicationUri(String.format("urn:example-client:%s", UUID.randomUUID()))
.setCertificate(loader.getClientCertificate()).setKeyPair(loader.getClientKeyPair())
.setEndpointUrl(endpointUrl).build();
return new UaTcpStackClient(config);
}
private OpcUaClient createUaClient() throws Exception {
KeyStoreLoader loader = createKeyStore();
if (loader == null) {
return null;
}
SecurityPolicy securityPolicy = client.getSecurityPolicy();
EndpointDescription[] endpoints = null;
try {
ServerOnNetwork[] servers = findServersOnNetwork(client.getEndpointUrl()).get();
ServerOnNetwork server = Arrays.stream(servers)
.filter(e -> e.getServerName().equals(client.getUaServerName())).findFirst()
.orElseThrow(() -> new Exception("no desired UA Server returned."));
endpoints = UaTcpStackClient.getEndpoints(server.getDiscoveryUrl()).get();
} catch (Throwable ex) {
ex.printStackTrace();
}
EndpointDescription endpoint = Arrays.stream(endpoints)
.filter(e -> e.getSecurityPolicyUri().equals(securityPolicy.getSecurityPolicyUri())).findFirst()
.orElseThrow(() -> new Exception("no desired endpoints returned"));
logger.info("Using endpoint: {} [{}]", endpoint.getEndpointUrl(), securityPolicy);
OpcUaClientConfig config = OpcUaClientConfig.builder()
.setApplicationName(LocalizedText.english("eclipse milo opc-ua client"))
.setApplicationUri("urn:eclipse:milo:examples:client").setCertificate(loader.getClientCertificate())
.setKeyPair(loader.getClientKeyPair()).setEndpoint(endpoint)
.setIdentityProvider(client.getIdentityProvider()).setRequestTimeout(uint(5000)).build();
return new OpcUaClient(config);
}
public void run() {
try {
OpcUaClient uaClient = createUaClient();
future.whenComplete((c, ex) -> {
if (ex != null) {
logger.error("Error running example: {}", ex.getMessage(), ex);
}
try {
uaClient.disconnect().get();
Stack.releaseSharedResources();
} catch (InterruptedException | ExecutionException e) {
logger.error("Error disconnecting:", e.getMessage(), e);
}
try {
Thread.sleep(1000);
System.exit(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
try {
client.run(uaClient, future);
future.get(15, TimeUnit.SECONDS);
} catch (Throwable t) {
logger.error("Error running client example: {}", t.getMessage(), t);
future.completeExceptionally(t);
}
} catch (Throwable t) {
logger.error("Error getting client: {}", t.getMessage(), t);
future.completeExceptionally(t);
try {
Thread.sleep(1000);
System.exit(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*
* try { Thread.sleep(999999999); } catch (InterruptedException e) {
* e.printStackTrace(); }
*/
}
}
I think you may be confused about what a Discovery Server does.
You don't connect "through" a Discovery Server to another server. It's more like a registry where other servers can register themselves and then clients can go and see what servers are available.
The client queries the discovery server for a list of servers, selects one, and then connects directly to that server using the information obtained from the discovery server.

Some server generated events do not get delivered to the client in production over websockets

Bottom line:
Some server generated events do not get delivered to the client in production over websockets. However, the websocket connections get established just fine.
Case study:
I open Google Chrome and connect to our server. Open the devtools. Under WS tab, I see that connection got established fine, but I receive no frames when, let’s say, server needs to update something on the page. I wait for a while and sometimes (only sometimes) I get some events with a huge amount of delay. This works as expected locally however.
Question:
Has anyone seen similar websocket behavior and has any suggestions on how to eliminate variables for this investigation.
Infrastructure:
Server: Linux Tomcat
Two servers that handle:
1. Traffic from Devices (Communicating over TCP/IP with the Server)
2. Traffic from Users
Users and Devices are many to many relationship. If a user gets connected to a server that doesn’t have a device connected. This server looks on the other server and handles the info exchange.
There is a firewall in front of the servers.
Code:
https://github.com/kino6052/websockets-issue
WebSocketServerEndpoint.java
#ServerEndpoint("/actions")
public class WebSocketServerEndpoint {
static private final org.slf4j.Logger logger = LoggerFactory.getLogger(WebSocketServerEndpoint.class);
#OnOpen
public void open(Session session) {
WebSocketSessionHandler.addSession(session);
}
#OnClose
public void close(Session session) {
WebSocketSessionHandler.removeSession(session);
}
#OnError
public void onError(Throwable error) {
//Logger.getLogger(WebSocketServerEndpoint.class.getName()).log(Level.SEVERE, null, error);
}
#OnMessage
public void handleMessage(String message, Session session) {
try (JsonReader reader = Json.createReader(new StringReader(message))) {
JsonObject jsonMessage = reader.readObject();
Long userId = null;
Long tenantId = null;
switch (WebSocketActions.valueOf(jsonMessage.getString("action"))){
case SaveUserId:
userId = getUserId(jsonMessage);
tenantId = getTenantId(jsonMessage);
Long userIdKey = WebSocketSessionHandler.saveUserId(userId, session);
Long tenantUserKey = WebSocketSessionHandler.saveTenantUser(tenantId, userId);
WebSocketSessionHandler.updateUserSessionKeys(session, tenantUserKey, userIdKey); // Needed for Making Weak Maps Keep Their Keys if Session is Currently Active
}
} catch (Exception e) {
logger.error(e.toString());
}
}
private Long getUserId(JsonObject jsonMessage) {
Long userId = null;
try {
userId = Long.parseLong(((Integer) jsonMessage.getInt("userId")).toString());
return userId;
} catch (Exception e) {
logger.error(e.getMessage());
return userId;
}
}
private Long getTenantId(JsonObject jsonMessage) {
Long tenantId = null;
try {
tenantId = Long.parseLong(((Integer) jsonMessage.getInt("tenantId")).toString());
return tenantId;
} catch (Exception e) {
logger.error(e.getMessage());
return tenantId;
}
}
}
WebSocketService.java
#Singleton
public class WebSocketService {
private static final Logger logger = LoggerFactory.getLogger(WebSocketService.class);
public enum WebSocketEvents{
OnConnection,
OnActivity,
OnAccesspointStatus,
OnClosedStatus,
OnConnectedStatus,
OnAlert,
OnSessionExpired
}
public enum WebSocketActions{
SaveUserId
}
#WebPost("/lookupWebSocketSessions")
public WebResponse lookupWebSocketSessions(#JsonArrayParam("userIds") List<Integer> userIds, #WebParam("message") String message){
try {
for (Integer userIdInt : userIds) {
Long userId = Long.parseLong(userIdInt.toString());
if (WebSocketSessionHandler.sendToUser(userId, message) == 0) {
} else {
//logger.debug("Couldn't Send to User");
}
}
} catch (ClassCastException e) {
//logger.error(e.getMessage());
return webResponseBuilder.fail(e);
} catch (Exception e) {
//logger.error(e.getMessage());
return webResponseBuilder.fail(e);
}
return webResponseBuilder.success(message);
}
#WebPost("/lookupWebSocketHistorySessions")
public WebResponse lookupWebSocketHistorySessions(#JsonArrayParam("userIds") List<Integer> userIds, #WebParam("message") String message){
try {
for (Integer userIdInt : userIds) {
Long userId = Long.parseLong(userIdInt.toString());
if (WebSocketHistorySessionHandler.sendToUser(userId, message) == 0) {
} else {
//logger.debug("Couldn't Send to User");
}
}
} catch (ClassCastException e) {
//logger.error(e.getMessage());
return webResponseBuilder.fail(e);
} catch (Exception e) {
//logger.error(e.getMessage());
return webResponseBuilder.fail(e);
}
return webResponseBuilder.success(message);
}
// Kick Out a User if Their Session is no Longer Valid
public void sendLogout(User user) {
try {
Long userId = user.getId();
List<Long> userIds = new ArrayList<>();
userIds.add(userId);
JSONObject result = new JSONObject();
result.put("userId", userId);
JSON message = WebSocketSessionHandler.createMessage(WebSocketEvents.OnSessionExpired, result);
lookOnOtherServers(userIds, message);
} catch (Exception e) {
logger.error("Couldn't Logout User");
}
}
// Send History after Processing Data
// Returns "0" if success, "-1" otherwise
public int sendHistory(Activity activity) {
try {
TimezoneService.TimeZoneConfig timeZoneConfig = timezoneService.getTimezoneConfigsByAp(null, activity.getAccesspointId());
JSONObject result = (JSONObject) JSONSerializer.toJSON(activity);
String timezoneId = timezoneService.convertTimezoneConfigToTimezoneId(timeZoneConfig);
result.put("timezoneString", timezoneId);
result.put(
"profileId",
userDao.getUserProfileId(activity.getUserId())
);
JSON message = WebSocketHistorySessionHandler.createMessage(WebSocketEvents.OnActivity, result);
List<Long> userIds = getUsersSubscribedToActivity(activity.getTenantId());
lookOnOtherServersHistory(userIds, message);
return 0;
} catch (Exception e) {
//logger.error("Couldn't Send History");
return -1;
}
}
// SendAlertUpdate after Processing Data
public void sendAlertUpdate(Alert alert) {
try {
List<Long> userIds = getUsersUnderTenantByAccesspointId(alert.getAccesspointId());
JSONObject result = JSONObject.fromObject(alert);
JSON message = WebSocketSessionHandler.createMessage(WebSocketEvents.OnAlert, result);
lookOnOtherServers(userIds, message);
} catch (Exception e) {
//logger.error("Couldn't Send Aleart");
}
}
// Send Connected Status after Processing Data
public void sendConnectedStatus(Long accesspointId, Boolean isConnected) {
try {
List<Long> userIds = getUsersUnderTenantByAccesspointId(accesspointId);
JSONObject result = new JSONObject();
result.put("accesspointId", accesspointId);
result.put("isConnected", isConnected);
JSON message = WebSocketSessionHandler.createMessage(WebSocketEvents.OnConnectedStatus, result);
lookOnOtherServers(userIds, message);
} catch (Exception e) {
//logger.error("Couldn't Send Connected Status");
}
}
public int sendHistory(CredentialActivity activity) {
try {
TimezoneService.TimeZoneConfig timeZoneConfig = timezoneService.getTimezoneConfigsByAp(null, activity.getAccesspointId());
JSONObject result = (JSONObject) JSONSerializer.toJSON(activity);
String timezoneId = timezoneService.convertTimezoneConfigToTimezoneId(timeZoneConfig);
result.put("timezoneString", timezoneId);
result.put(
"profileId",
userDao.getUserProfileId(activity.getUserId())
);
JSON message = WebSocketHistorySessionHandler.createMessage(WebSocketEvents.OnActivity, result);
List<Long> userIds = getUsersUnderTenantByAccesspointId(activity.getAccesspointId());
lookOnOtherServersHistory(userIds, message);
return 0;
} catch (Exception e) {
return -1;
}
}
public Boolean isUserSessionAvailable(Long id) {
return WebSocketSessionHandler.isUserSessionAvailable(id);
}
public void lookOnOtherServers(List<Long> userId, JSON data){
List<String> urls = awsService.getServerURLs();
for (String url : urls) {
postJSONDataToUrl(url, userId, data);
}
}
public void lookOnOtherServersHistory(List<Long> userId, JSON data){
List<String> urls = awsService.getServerURLsHistory();
for (String url : urls) {
postJSONDataToUrl(url, userId, data);
}
}
public int sendClosedStatus(AccesspointStatus accesspointStatus){
try {
JSONObject accesspointStatusJSON = new JSONObject();
accesspointStatusJSON.put("accesspointId", accesspointStatus.getAccesspointId());
accesspointStatusJSON.put("openStatus", accesspointStatus.getOpenStatus());
List<Long> userIds = getUsersUnderTenantByAccesspointId(accesspointStatus.getAccesspointId());
lookOnOtherServers(userIds, accesspointStatusJSON);
return 0;
} catch (Exception e) {
return -1;
}
}
public List<Long> getUsersSubscribedToActivity(Long tenantId) {
List<Long> userList = WebSocketSessionHandler.getUsersForTenant(tenantId);
return userList;
}
private List<Long> getUsersUnderTenantByAccesspointId(Long accesspointId) {
List<Long> userList = new ArrayList<>();
User user = userDao.getBackgroundUserByAccesspoint(accesspointId);
List<Record> recordList = tenantDao.getTenantsByUser(user, user.getId());
for (Record record : recordList) {
Long tenantId = (Long) record.get("id");
userList.addAll(getUsersSubscribedToActivity(tenantId));
}
return userList;
}
public void postJSONDataToUrl(String url, List<Long> userId, JSON data) throws AppException {
List<NameValuePair> parameters;
HttpResponse httpResponse;
HttpClientService.SimpleHttpClient simpleHttpClient = httpClientService.createHttpClient(url);
try {
parameters = httpClientService.convertJSONObjectToNameValuePair(userId, data);
} catch (Exception e) {
throw new AppException("Couldn't Convert Input Parameters");
}
try {
httpResponse = simpleHttpClient.sendHTTPPost(parameters);
} catch (Exception e) {
throw new AppException("Couldn't Get Data from the Server");
}
if (httpResponse == null) {
throw new AppException("Couldn't Send to Another Server");
} else {
//logger.error(httpResponse.getStatusLine().toString());
}
}
}
WebSocketSessionHandler.java
public class WebSocketSessionHandler {
// Apparently required to instantiate the dialogue,
// ideally it would be better to just create session map where sessions are mapped to userId,
// however, userId will be send only after the session is created.
// TODO: Investigate Instantiation of WebSocket Session Further
// WeakHashMap is Used for Automatic Memory Management (So That Removal of Keys That are no Longer Used Can be Automatically Performed)
// NOTE: However, it Requires Certain Precautions to Make Sure Their Keys Don't Expire Unexpectedly, Look for the Commented Code Below
private static final Map<Long, Set<Session>> sessionMap = new WeakHashMap<>();
private static final Map<Long, Set<Long>> tenantUserMap = new WeakHashMap<>();
public WebSocketSessionHandler() {}
public static List<Long> getUsersForTenant(Long tenantId) {
List<Long> userIds = new ArrayList<>();
Set<Long> userIdsSet = tenantUserMap.get(tenantId);
if (userIdsSet != null) {
for (Long userId : userIdsSet){
userIds.add(userId);
}
}
return userIds;
}
public static Boolean isUserSessionAvailable(Long id){
Set<Session> userSessions = sessionMap.get(id);
if (userSessions == null || userSessions.size() == 0) {
return false;
} else {
return true;
}
}
// addSession() should add "session" to "sessions" set
// returns: "0" if success and "-1" otherwise
public static int addSession(Session session) {
int output;
try {
final long ONE_DAY = 86400000;
session.setMaxIdleTimeout(ONE_DAY);
sessions.put(session, new ArrayList<>());
return sendToSession(session, createMessage(WebSocketEvents.OnConnection, "Successfully Connected"));
} catch (Exception e) {
logger.error("Couldn't Add Session");
return -1;
}
}
// removeSession() should remove "session" from "sessions" set
// Scenarios:
// sessions is null?
// returns: "0" if success and "-1" otherwise
public static int removeSession( Session session) {
try {
closeSessionProperly(session);
if (sessions.remove(session) != null) {
return 0;
} else {
return -1;
}
} catch (Exception e) {
logger.error("Couldn't Remove Session");
return -1;
}
}
private static void closeSessionProperly(Session session) {
try {
session.close();
} catch (IOException ex) {
}
}
public static Long getKeyFromMap(Map map, Long key){ // Needed for Weak Maps
Set<Long> keySet = map.keySet();
for (Long keyReference : keySet) {
if (keyReference == key) {
return keyReference;
}
}
return key; // If Not Found Return the Value Passed in
}
// saveUserId() should create an { userId -> session } entry in sessionMap
public static Long saveUserId(Long userId, Session session){
// Test Scenarios:
// Can userId be null or wrong?
// Can session be null or wrong?
try {
userId = getKeyFromMap(sessionMap, userId); // Required for Weak Maps to Work Correctly
Set<Session> sessionsForUser = sessionMap.get(userId);
if (sessionsForUser == null) {
sessionsForUser = new HashSet<>();
}
sessionsForUser.add(session);
sessionMap.put(userId, sessionsForUser);
return userId;
} catch (Exception e) {
logger.error("Couldn't Save User Id");
return null;
}
}
// saveUserId() should create an { userId -> session } entry in sessionMap
public static Long saveTenantUser(Long tenantId, Long userId){
// Test Scenarios:
// Can userId be null or wrong?
// Can session be null or wrong?
try {
tenantId = getKeyFromMap(tenantUserMap, tenantId); // Required for Weak Maps to Work Correctly
Set<Long> users = tenantUserMap.get(tenantId);
if (users == null) {
users = new HashSet<>();
}
users.add(userId);
tenantUserMap.put(tenantId, users);
return tenantId;
} catch (Exception e) {
logger.error("Couldn't Save Tenant User");
return null;
}
}
public static void updateUserSessionKeys(Session session, Long tenantId, Long userId) {
try {
List<Long> userSessionKeys = sessions.get(session);
userSessionKeys.add(0, tenantId);
userSessionKeys.add(1, userId);
} catch (Exception e) {
logger.error("Couldn't Update User Session Keys");
}
}
// removeUserId() should remove an { userId -> session } entry in sessionMap
// returns: "0" if success and "-1" otherwise
public static int removeUserId( Long userId) {
try {
sessionMap.remove(userId);
return 0;
} catch (Exception e) {
return -1;
}
}
// sendAccesspointStatus() should compose JSON message and pass it to sendToUser()
// returns: "0" if success and "-1" otherwise
public static int sendClosedStatus(Long userId, JSONObject accesspointStatus) {
try {
JSONObject accesspointStatusEventMessage = (JSONObject) createMessage(WebSocketEvents.OnClosedStatus, accesspointStatus);
sendToUser(userId, accesspointStatusEventMessage);
return 0;
} catch (Exception e) {
return -1;
}
}
// sendToUser() sends message to session that is mapped to userId
// returns: "0" if success and "-1" otherwise
public static int sendToUser( Long userId, JSON message) {
if (sessionMap.containsKey(userId)) {
Set<Session> sessionsForUser = sessionMap.get(userId);
for (Session session : sessionsForUser) {
if (!session.isOpen()) {
sessions.remove(session);
continue;
}
sendToSession(session, message);
}
return 0;
} else {
return -1;
}
}
// sendToSession() sends string message to session
// returns: "0" if success and "-1" otherwise
private static int sendToSession( Session session, JSON message){
try {
try {
Long tenantId = sessions.get(session).get(0);
((JSONObject) message).put("tenantId", tenantId);
} catch (Exception e) {
logger.error("No tenantId Found");
}
session.getBasicRemote().sendText(message.toString());
return 0;
} catch (IOException e) {
try {
session.close();
} catch (IOException ex) {
}
closeSessionProperly(session);
sessions.remove(session);
return -1;
}
}
// sendToSession() sends string message to session
// returns: "0" if success and "-1" otherwise
private static int sendToSession( Session session, String message){
try {
JSONObject newMessage = JSONObject.fromObject(message);
try {
Long tenantId = sessions.get(session).get(0);
newMessage.put("tenantId", tenantId);
} catch (Exception e) {
logger.error("No tenantId Found");
}
session.getBasicRemote().sendText(newMessage.toString());
return 0;
} catch (IOException e) {
closeSessionProperly(session);
sessions.remove(session);
return -1;
}
}
}
Probably not the only bug, but your WebSocketSessionHandler class is not thread-safe. It uses WeakHashMap internally which is not synchronized. Concurrent access to these maps may result in unexpected behavior, which may or may not cause the effects you are seeing.
Turns out this was a correct assumption. A general rule of thumb: Unexpected Behaviour ~ Race Condition
Probably not the only bug, but your WebSocketSessionHandler class is not thread-safe. It uses WeakHashMap internally which is not synchronized. Concurrent access to these maps may result in unexpected behavior, which may or may not cause the effects you are seeing.
(copied from my comment. Turns out this was the solution)

Firebase Java Admin SDK don't work

I am following the documentation on Firebase website on setting up an Java Admin SDK. So I add the dependency to the build.gradle, and added the following code:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.auth.FirebaseCredentials;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
public class Main {
public static void main(String[] args) throws FileNotFoundException{
FileInputStream serviceAccount = new FileInputStream("/Users/idanaviv10/Desktop/mapit-33290-firebase-adminsdk-fdy24-a1d0505493.json");
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredential(FirebaseCredentials.fromCertificate(serviceAccount))
.setDatabaseUrl("https://mapit-33290.firebaseio.com/")
.build();
FirebaseApp.initializeApp(options);
final FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("server/saving-data/fireblog");
DatabaseReference usersRef = ref.child("users");
Map<String, User> users = new HashMap<String, User>();
users.put("alanisawesome", new User("June 23, 1912", "Alan Turing"));
users.put("gracehop", new User("December 9, 1906", "Grace Hopper"));
usersRef.setValue(users);
}
public static class User {
public String date_of_birth;
public String full_name;
public String nickname;
public User(String date_of_birth, String full_name) {
// ...
}
public User(String date_of_birth, String full_name, String nickname) {
// ...
}
}
}
The problem is when I am trying to get data (adding a listener) or trying to save data (like in the example) nothing happened. I am running the code in eclipse, I can see in the console that it print "Done", but when I check the database (on the firebase console on the browser) nothing change.
I found the problem, the problem was that the program will terminate before connecting to the Firebase server. What you need to do is to delay the termination of the program, by either calling Thread.sleep(20000);, or like I did it
Scanner scanner = new Scanner(System.in);
while(!scanner.nextLine().equals("Quit")){}
System.exit(0);
One other thing you can try is to explicitly wait until the setValue() task is complete using the Tasks API:
Task<Void> task = usersRef.setValue(users);
try {
Tasks.await(task);
} catch (ExecutionException | InterruptedException e) {
// Handle error if necessary
}
below code is pushing data into firebase database using java async call api from firebase sdk but listeners code is not executing . I am running below code in server side backend.
public enum Firebase {
INSTANCE;
FirebaseApp firebaseApp;
public void initilizeFirebaseApp(ConfigLoader configReader) {
CountDownLatch done = new CountDownLatch(1);
final AtomicInteger message1 = new AtomicInteger(0);
InputStream firebaseSecret = getClass().getClassLoader().getResourceAsStream("ServiceAccount.json");
final GoogleCredentials credentials;
try {
credentials = GoogleCredentials.fromStream(firebaseSecret);
} catch (IOException e) {
e.printStackTrace();
System.out.println("Error while reading Firebase config file." + e.toString());
throw new IllegalStateException(e);
}
Map<String, Object> auth = new HashMap<>();
auth.put("uid", "my_resources");
FirebaseOptions options = new Builder()
.setConnectTimeout(1000)
.setCredentials(credentials)
.setDatabaseAuthVariableOverride(auth)
.setDatabaseUrl(configReader.getFirebaseDatabaseURL())
.setStorageBucket(configReader.getFirebaseStorageBucket())
.setProjectId(configReader.getFirebseProjectId())
.build();
firebaseApp = FirebaseApp.initializeApp(options);
System.out.println(firebaseApp.getName());
//System.out.println(firebaseApp.getName());
// Use the shorthand notation to retrieve the default app's service
FirebaseAuth defaultAuth = FirebaseAuth.getInstance();
FirebaseDatabase defaultDatabase = FirebaseDatabase.getInstance();
// The app only has access as defined in the Security Rules
DatabaseReference ref = FirebaseDatabase
.getInstance()
.getReference("/analyst_profiles");
DateTime dt = new DateTime(java.util.Date.from(Instant.now()), java.util.TimeZone.getDefault());
System.out.println(dt.getValue());
//test data push
// https://firebase.google.com/docs/database/admin/save-data
AnalystProfiles analystProfilesObjTemp = new AnalystProfiles("test2", Long.toString(dt.getValue()), "dsds", "ds", "ds",
"dsa2323", "32ddss232");
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
AnalystProfiles post = dataSnapshot.getValue(AnalystProfiles.class);
System.out.println(post);
//done.countDown();
}
#Override
public void onCancelled(DatabaseError databaseError) {
System.out.println("The read failed: " + databaseError.getCode());
}
});
CompletableFuture<String> welcomeText = CompletableFuture.supplyAsync(() -> {
try {
ref.push().setValueAsync(analystProfilesObjTemp).get();
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException("Error while waiting for future", e);
}
return "ok";
}).thenApply(x -> {
System.out.println(x);
System.out.println("Listeners code is not executing");
return x;
});
done.countDown();
try {
System.out.println(welcomeText.get());
done.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
public void testdataLoad() {
// The app only has access as defined in the Security Rules
DatabaseReference ref = FirebaseDatabase
.getInstance()
.getReference("/analyst_profiles");
DateTime dt = new DateTime(java.util.Date.from(Instant.now()), java.util.TimeZone.getDefault());
System.out.println(dt.getValue());
//test data push
// https://firebase.google.com/docs/database/admin/save-data
AnalystProfiles analystProfilesObjTemp = new AnalystProfiles("test2", Long.toString(dt.getValue()), "dsds", "ds", "ashutsh",
"dsa2323", "32ddss232");
CompletableFuture<String> welcomeText = CompletableFuture.supplyAsync(() -> {
try {
ref.push().setValueAsync(analystProfilesObjTemp).get();
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException("Error while waiting for future", e);
}
return "ok";
}).thenApply(x -> {
System.out.println(x);
return x;
});
try {
System.out.println(welcomeText.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
Add this code:
ApiFuture api=/*your reference to database*/usersRef.setValueAsync(users/*the data*/);
Object o = api.get(/*time out*/8,TimeUnit.SECONDS/*unite for time out her is seconds*/);
And at last you can check with
api.isDone();

Categories

Resources