@@ -51,8 +51,8 @@ Software and the Larger Work(s), and to sublicense the foregoing rights on
5151
5252import io .micronaut .context .annotation .Property ;
5353import io .micronaut .context .event .ShutdownEvent ;
54- import io .micronaut .context .event .StartupEvent ;
5554import io .micronaut .runtime .event .annotation .EventListener ;
55+ import jakarta .annotation .PostConstruct ;
5656import jakarta .inject .Inject ;
5757import jakarta .inject .Singleton ;
5858import jakarta .validation .constraints .NotEmpty ;
@@ -75,25 +75,29 @@ public class DeviceModelInstancesCache {
7575 // we we don't know about this then we will try an individual load
7676 public final static String SELECT_MODEL_NAME_BY_MODEL_ID = "SELECT JSON_VALUE(dtm.data, '$.displayName' ) AS modelname FROM digital_twin_models dtm WHERE JSON_VALUE (dtm.data, '$._id' ) = ? " ;
7777 public final static String SELECT_MODEL_ID_BY_MODEL_NAME = "SELECT JSON_VALUE (dtm.data, '$._id' ) AS modelid FROM digital_twin_models dtm WHERE JSON_VALUE(dtm.data, '$.displayName' ) = ? " ;
78- public final static String SELECT_MODEL_ID_DISPLAY_NAME_AND_EXTERNAL_KEY_BY_INSTANCE_ID = "SELECT JSON_VALUE (dti.data, '$.digitalTwinModelId' ) AS modelid, JSON_VALUE (dti.data, '$.externalKey' ) AS externalkey, JSON_VALUE(dti.data, '$.displayName' ) FROM digital_twin_instances dti WHERE JSON_VALUE(dti.data, '$._id' ) = ?" ;
78+ public final static String SELECT_MODEL_ID_DISPLAY_NAME_AND_EXTERNAL_KEY_BY_INSTANCE_ID = "SELECT JSON_VALUE (dti.data, '$.digitalTwinModelId' ) AS modelid, JSON_VALUE (dti.data, '$.externalKey' ) AS externalkey, JSON_VALUE(dti.data, '$.displayName' )AS displayname FROM digital_twin_instances dti WHERE JSON_VALUE(dti.data, '$._id' ) = ?" ;
79+ public final static String SELECT_MODEL_ID_INSTANCE_ID_AND_EXTERNAL_KEY_BY_INSTANCE_DISPLAY_NAME = "SELECT JSON_VALUE (dti.data, '$.digitalTwinModelId' ) AS modelid, JSON_VALUE (dti.data, '$.externalKey' ) AS externalkey, JSON_VALUE (dti.data, '$._id' ) AS instanceid FROM digital_twin_instances dti WHERE JSON_VALUE(dti.data, '$.displayName' ) = ?" ;
7980
8081 private final String schemaName ;
8182 private final DBConnectionSupplier dbConnectionSupplier ;
8283 private Connection connection ;
8384
8485 private final Map <String , String > instanceIdToModelId = Collections .synchronizedMap (new HashMap <>());
8586 private final Map <String , String > instanceIdToExternalKey = Collections .synchronizedMap (new HashMap <>());
86- private final Map <String , String > instanceIdToInstanceName = Collections .synchronizedMap (new HashMap <>());
87+ private final Map <String , String > instanceIdToInstanceDisplayName = Collections .synchronizedMap (new HashMap <>());
88+ private final Map <String , String > instanceDisplayNameToInstanceId = Collections .synchronizedMap (new HashMap <>());
8789 private final Map <String , String > instanceIdToModelName = Collections .synchronizedMap (new HashMap <>());
8890 private final Map <String , String > externalKeyToInstanceId = Collections .synchronizedMap (new HashMap <>());
8991 private final Map <String , String > modelIdToModelName = Collections .synchronizedMap (new HashMap <>());
9092 private final Map <String , String > modelNameToModelId = Collections .synchronizedMap (new HashMap <>());
9193 private final Set <String > foundMissingModelIds = Collections .synchronizedSet (new HashSet <>());
9294 private final Set <String > foundMissingModelNames = Collections .synchronizedSet (new HashSet <>());
9395 private final Set <String > foundMissingInstanceIds = Collections .synchronizedSet (new HashSet <>());
96+ private final Set <String > foundMissingInstanceDisplayNames = Collections .synchronizedSet (new HashSet <>());
9497 private final Set <String > foundMissingExternalKeys = Collections .synchronizedSet (new HashSet <>());
9598
96- private PreparedStatement selectModelIdByInstanceIdPS ;
99+ private PreparedStatement selectInstanceDetailsByInstanceIdPS ;
100+ private PreparedStatement selectInstanceDetailsByInstanceDisplayNamePS ;
97101 private PreparedStatement selectModelNameByModelIdPS ;
98102 private PreparedStatement selectModelIdByModelNamePS ;
99103 private final boolean preloadExistingModels ;
@@ -113,9 +117,9 @@ public DeviceModelInstancesCache(DBConnectionSupplier dbConnectionSupplier,
113117 this .preloadExistingInstances = preloadExistingInstances ;
114118 }
115119
116- @ EventListener
117- public void onStartup ( StartupEvent event ) {
118- log .info ("Startup event received for DeviceModelInstancesCache" );
120+ @ PostConstruct
121+ public void postConstruct ( ) {
122+ log .info ("Post Construct event received for DeviceModelInstancesCache" );
119123 try {
120124 configure ();
121125 } catch (Exception e ) {
@@ -149,8 +153,10 @@ public void configure() throws Exception {
149153 // set this up so we can re-use it later if we need to query for an instance we
150154 // didn't know about
151155 log .fine ("Creating prepared statements" );
152- selectModelIdByInstanceIdPS = connection
156+ selectInstanceDetailsByInstanceIdPS = connection
153157 .prepareStatement (SELECT_MODEL_ID_DISPLAY_NAME_AND_EXTERNAL_KEY_BY_INSTANCE_ID );
158+ selectInstanceDetailsByInstanceDisplayNamePS = connection
159+ .prepareStatement (SELECT_MODEL_ID_INSTANCE_ID_AND_EXTERNAL_KEY_BY_INSTANCE_DISPLAY_NAME );
154160 selectModelNameByModelIdPS = connection .prepareStatement (SELECT_MODEL_NAME_BY_MODEL_ID );
155161 selectModelIdByModelNamePS = connection .prepareStatement (SELECT_MODEL_ID_BY_MODEL_NAME );
156162 log .fine ("Prepared statements created" );
@@ -360,7 +366,16 @@ private void preloadExistingInstances() throws SQLException {
360366 String instanceDisplayName = rs .getString (INSTANCE_ID_COLUMN_DISPLAY_NAME );
361367 String modelName = modelIdToModelName .get (modelIdExistingInstance );
362368 instanceIdToModelId .put (instanceIdExistingInstance , modelIdExistingInstance );
363- instanceIdToInstanceName .put (instanceIdExistingInstance , instanceDisplayName );
369+ instanceIdToInstanceDisplayName .put (instanceIdExistingInstance , instanceDisplayName );
370+ if (instanceDisplayNameToInstanceId .containsKey (instanceDisplayName )) {
371+ log .warning ("Instance display name cache already contains key " + instanceDisplayName
372+ + " connected to instance id " + instanceDisplayNameToInstanceId .get (instanceDisplayName )
373+ + ", duplicates are not added" );
374+ } else {
375+ instanceDisplayNameToInstanceId .put (instanceDisplayName , instanceIdExistingInstance );
376+ log .info ("Added instance name " + instanceDisplayName + " to instanceId "
377+ + instanceIdExistingInstance + " mapping" );
378+ }
364379 log .info ("Added instance id " + instanceIdExistingInstance + " named " + instanceDisplayName
365380 + " to modelId " + modelIdExistingInstance + " mapping" );
366381 instanceIdToModelName .put (instanceIdExistingInstance , modelName );
@@ -451,10 +466,10 @@ public String getInstanceDisplayNameByInstanceId(@NotNull @NotEmpty String insta
451466 }
452467 // do we already have the info ? note that empty string and null are valid
453468 // responses here.
454- if (instanceIdToInstanceName .containsKey (instanceId )) {
469+ if (instanceIdToInstanceDisplayName .containsKey (instanceId )) {
455470 // we have the key, the model could be a string, null blank etc if one hasn't
456471 // been set, but that's still valid.
457- return instanceIdToInstanceName .get (instanceId );
472+ return instanceIdToInstanceDisplayName .get (instanceId );
458473 }
459474 // we don't have a cached version
460475 // let's try and locate it
@@ -474,6 +489,54 @@ public String getInstanceDisplayNameByInstanceId(@NotNull @NotEmpty String insta
474489 }
475490 }
476491
492+ /**
493+ * try to get the modelId from the cache or if there is no cachedata
494+ *
495+ * @param instanceId the instance to locate
496+ * @param cacheMissingResults if true and we already have looked but not found
497+ * this then don't look again
498+ * @return the instance display name is there is one
499+ * @throws MissingInstanceException throws an exception if we can't locate the
500+ * instance (either in the known missing cache
501+ * if cacheMissingResults is true, or in the
502+ * IoT service otherwise)
503+ * @throws SQLException if there was a problem querying the iot
504+ * service
505+ */
506+ public String getInstanceIdByInstanceDisplayName (@ NotNull @ NotEmpty String instanceDisplayName ,
507+ boolean cacheMissingResults ) throws MissingInstanceException , SQLException {
508+ boolean knownMissing = foundMissingInstanceDisplayNames .contains (instanceDisplayName );
509+ // are we looking at the cache ?
510+ if (cacheMissingResults && knownMissing ) {
511+ // we know it's missing, and we are not checking an other time
512+ throw new MissingInstanceException (
513+ "No instance found in cache and not checking again for instanceDisplayName" + instanceDisplayName );
514+ }
515+ // do we already have the info ? note that empty string and null are valid
516+ // responses here.
517+ if (instanceDisplayNameToInstanceId .containsKey (instanceDisplayName )) {
518+ // we have the key, the model could be a string, null blank etc if one hasn't
519+ // been set, but that's still valid.
520+ return instanceDisplayNameToInstanceId .get (instanceDisplayName );
521+ }
522+ // we don't have a cached version
523+ // let's try and locate it
524+ try {
525+ InstanceKeyInfo ike = loadInstanceByInstanceDisplayName (instanceDisplayName );
526+ // OK we have something, was it previously tagged as knownMissing ? if so remove
527+ // the id
528+ if (knownMissing ) {
529+ foundMissingInstanceDisplayNames .remove (instanceDisplayName );
530+ }
531+ return ike .getInstanceId ();
532+ } catch (MissingInstanceException e ) {
533+ // cache the missing result for later use
534+ foundMissingInstanceDisplayNames .add (instanceDisplayName );
535+ // then throw the exception
536+ throw e ;
537+ }
538+ }
539+
477540 /**
478541 * try to get the external key from the cache or if there is no cachedata
479542 *
@@ -568,10 +631,10 @@ public String getModelNameByInstanceId(@NotNull @NotEmpty String instanceId, boo
568631 */
569632 private InstanceKeyInfo loadInstanceByInstanceId (@ NotNull @ NotEmpty String instanceId )
570633 throws SQLException , MissingInstanceException {
571- synchronized (selectModelIdByInstanceIdPS ) {
572- selectModelIdByInstanceIdPS .setString (1 , instanceId );
634+ synchronized (selectInstanceDetailsByInstanceIdPS ) {
635+ selectInstanceDetailsByInstanceIdPS .setString (1 , instanceId );
573636 // get all of the results
574- try (ResultSet rs = selectModelIdByInstanceIdPS .executeQuery ()) {
637+ try (ResultSet rs = selectInstanceDetailsByInstanceIdPS .executeQuery ()) {
575638 if (rs .next ()) {
576639 String modelId = rs .getString (MODEL_ID_COLUMN_NAME );
577640 String externalKey = rs .getString (EXTERNAL_KEY_COLUMN_NAME );
@@ -580,7 +643,15 @@ private InstanceKeyInfo loadInstanceByInstanceId(@NotNull @NotEmpty String insta
580643 instanceIdToModelId .put (instanceId , modelId );
581644 instanceIdToModelName .put (instanceId , modelName );
582645 instanceIdToExternalKey .put (instanceId , externalKey );
583- instanceIdToInstanceName .put (instanceId , instanceDisplayName );
646+ instanceIdToInstanceDisplayName .put (instanceId , instanceDisplayName );
647+ if (instanceDisplayNameToInstanceId .containsKey (instanceDisplayName )) {
648+ log .warning ("Instance display name cache already contains key " + instanceDisplayName
649+ + " connected to instance id "
650+ + instanceDisplayNameToInstanceId .get (instanceDisplayName )
651+ + ", duplicates are not added" );
652+ } else {
653+ instanceDisplayNameToInstanceId .put (instanceDisplayName , instanceId );
654+ }
584655 externalKeyToInstanceId .put (externalKey , instanceId );
585656 return new InstanceKeyInfo (instanceId , modelId , externalKey , instanceDisplayName );
586657 } else {
@@ -593,6 +664,51 @@ private InstanceKeyInfo loadInstanceByInstanceId(@NotNull @NotEmpty String insta
593664 }
594665 }
595666
667+ /**
668+ * on demand load an entry in the mode details cache
669+ *
670+ * @param instanceId
671+ * @throws SQLException
672+ * @throws MissingInstanceException
673+ * @return the located modelId, null for instances with no model
674+ */
675+ private InstanceKeyInfo loadInstanceByInstanceDisplayName (@ NotNull @ NotEmpty String instanceDisplayName )
676+ throws SQLException , MissingInstanceException {
677+ synchronized (selectInstanceDetailsByInstanceDisplayNamePS ) {
678+ selectInstanceDetailsByInstanceDisplayNamePS .setString (1 , instanceDisplayName );
679+ // get all of the results
680+ try (ResultSet rs = selectInstanceDetailsByInstanceDisplayNamePS .executeQuery ()) {
681+ if (rs .next ()) {
682+ String modelId = rs .getString (MODEL_ID_COLUMN_NAME );
683+ String externalKey = rs .getString (EXTERNAL_KEY_COLUMN_NAME );
684+ String instanceId = rs .getString (INSTANCE_ID_COLUMN_NAME );
685+ String modelName = modelIdToModelName .get (modelId );
686+ instanceIdToModelId .put (instanceId , modelId );
687+ instanceIdToModelName .put (instanceId , modelName );
688+ instanceIdToExternalKey .put (instanceId , externalKey );
689+ instanceIdToInstanceDisplayName .put (instanceId , instanceDisplayName );
690+ if (instanceDisplayNameToInstanceId .containsKey (instanceDisplayName )) {
691+ log .warning ("Instance display name cache already contains key " + instanceDisplayName
692+ + " connected to instance id "
693+ + instanceDisplayNameToInstanceId .get (instanceDisplayName )
694+ + ", duplicates are not added" );
695+ } else {
696+ instanceDisplayNameToInstanceId .put (instanceDisplayName , instanceId );
697+ }
698+ externalKeyToInstanceId .put (externalKey , instanceId );
699+ return new InstanceKeyInfo (instanceId , modelId , externalKey , instanceDisplayName );
700+ } else {
701+ throw new MissingInstanceException ("No instance found for instance id " + instanceDisplayName );
702+ }
703+ } catch (SQLException e ) {
704+ log .severe (
705+ "SQLException getting existing model / instance mappings in loadInstanceByInstanceDisplayName, "
706+ + e .getLocalizedMessage ());
707+ throw e ;
708+ }
709+ }
710+ }
711+
596712 @ Data
597713 @ AllArgsConstructor
598714 private class InstanceKeyInfo {
@@ -623,6 +739,7 @@ public void unconfigure() throws Exception {
623739 foundMissingModelIds .clear ();
624740 foundMissingModelNames .clear ();
625741 foundMissingInstanceIds .clear ();
742+ foundMissingInstanceDisplayNames .clear ();
626743 foundMissingExternalKeys .clear ();
627744 configured = false ;
628745 }
@@ -639,6 +756,7 @@ public String getConfig() {
639756 + modelIdToModelName + ")" + " model ids, " + modelNameToModelId .size () + " ( " + modelNameToModelId
640757 + ")" + " model names, " + foundMissingModelIds .size () + " found missing model ids"
641758 + foundMissingModelNames .size () + " found missing model names, " + foundMissingInstanceIds .size ()
759+ + " found missing instance display names, " + foundMissingInstanceDisplayNames .size ()
642760 + " found missing instance ids. preloadExistingModels=" + preloadExistingModels
643761 + ", preloadExistingInstances=" + preloadExistingInstances ;
644762 }
0 commit comments