@@ -55,8 +55,13 @@ public class NahimaManager extends AbstractRestClient {
5555 private static final Logger log =
5656 LoggerFactory .getLogger (NahimaManager .class );
5757 private final String url ;
58+ private final String baseUrl ;
5859 private final String username ;
5960 private final String password ;
61+ private final String clientId ;
62+ private final String clientSecret ;
63+ private final boolean useOAuth ;
64+ private final String tokenParamName ;
6065 private final boolean interactive ;
6166 private final ConcurrentHashMap <String , Map <String , JSONObject >>
6267 resolveCache = new ConcurrentHashMap <>();
@@ -65,27 +70,49 @@ public class NahimaManager extends AbstractRestClient {
6570 public NahimaManager (String url , String username , String password ,
6671 boolean interactive )
6772 throws IOException , InterruptedException {
68- this (url , username , password , interactive , true );
73+ this (url , username , password , null , null , interactive , true );
6974 }
7075
7176 public NahimaManager (String url , String username , String password ,
7277 boolean interactive , boolean requiresLogin )
7378 throws IOException , InterruptedException , RuntimeException {
79+ this (url , username , password , null , null , interactive , requiresLogin );
80+ }
81+
82+ public NahimaManager (String url , String username , String password ,
83+ String clientId , String clientSecret ,
84+ boolean interactive )
85+ throws IOException , InterruptedException , RuntimeException {
86+ this (url , username , password , clientId , clientSecret , interactive , true );
87+ }
88+
89+ public NahimaManager (String url , String username , String password ,
90+ String clientId , String clientSecret ,
91+ boolean interactive , boolean requiresLogin )
92+ throws IOException , InterruptedException , RuntimeException {
7493 // normalize URL
7594 if (!url .endsWith ("/" )) {
7695 url = url + "/" ;
7796 }
78- if (!url .endsWith ("api/v1/" )) {
79- url = url + "api/v1/" ;
80- }
97+
98+ this .baseUrl = url ;
99+ this .clientId = clientId ;
100+ this .clientSecret = clientSecret ;
101+ this .useOAuth = !isNullOrBlank (clientId ) && !isNullOrBlank (clientSecret );
102+ this .tokenParamName = useOAuth ? "access_token" : "token" ;
103+
81104 // store properties
82- this .url = url ;
105+ this .url = this . baseUrl + ( useOAuth ? "api/" : "api/v1/" ) ;
83106 this .username = username ;
84107 this .password = password ;
85108 this .interactive = interactive ;
86109
87- this .startSessionAndRetrieveToken ();
88- this .login ();
110+ if (useOAuth ) {
111+ this .retrieveOAuthToken ();
112+ } else {
113+ this .startSessionAndRetrieveToken ();
114+ this .login ();
115+ }
89116 }
90117
91118 /**
@@ -146,6 +173,9 @@ protected void startSessionAndRetrieveToken() throws RuntimeException {
146173 */
147174 protected void login ()
148175 throws IOException , InterruptedException , RuntimeException {
176+ if (useOAuth ) {
177+ return ;
178+ }
149179 String queryUrl =
150180 this .url + "session/authenticate?method=easydb&token=" + this .token ;
151181 HashMap <String , String > params = new HashMap <>();
@@ -167,6 +197,56 @@ protected void login()
167197 }
168198 }
169199
200+ protected void retrieveOAuthToken ()
201+ throws IOException , InterruptedException , RuntimeException {
202+ String queryUrl = this .baseUrl + "api/oauth2/token" ;
203+ HashMap <String , String > params = new HashMap <>();
204+ params .put ("grant_type" , "password" );
205+ params .put ("username" , this .username );
206+ params .put ("password" , this .password );
207+ params .put ("client_id" , this .clientId );
208+ params .put ("client_secret" , this .clientSecret );
209+
210+ String response = this .postRequest (queryUrl , params );
211+ JSONObject responseObject = new JSONObject (response );
212+ if (responseObject .has ("error" )) {
213+ throw new RuntimeException (
214+ "Failed to acquire OAuth2 token. Error: " +
215+ responseObject .optString ("error" ) +
216+ (responseObject .has ("error_description" )
217+ ? ": " + responseObject .optString ("error_description" )
218+ : "" ));
219+ }
220+ if (!responseObject .has ("access_token" )) {
221+ throw new RuntimeException (
222+ "Failed to acquire OAuth2 token: missing access_token in response." );
223+ }
224+ this .token = responseObject .getString ("access_token" );
225+ }
226+
227+ private boolean isNullOrBlank (String value ) {
228+ return value == null || value .trim ().isEmpty ();
229+ }
230+
231+ private String buildAuthenticatedUrl (String endpoint ) {
232+ return buildAuthenticatedUrl (endpoint , null );
233+ }
234+
235+ private String buildAuthenticatedUrl (String endpoint , String queryParams ) {
236+ StringBuilder urlBuilder = new StringBuilder ();
237+ urlBuilder .append (this .url );
238+ urlBuilder .append (endpoint );
239+ urlBuilder .append ("?" );
240+ urlBuilder .append (tokenParamName );
241+ urlBuilder .append ("=" );
242+ urlBuilder .append (this .token );
243+ if (queryParams != null && !queryParams .trim ().isEmpty ()) {
244+ urlBuilder .append ("&" );
245+ urlBuilder .append (queryParams );
246+ }
247+ return urlBuilder .toString ();
248+ }
249+
170250 /**
171251 * This function loops the images in a Specimen and uploads them to Nahima
172252 *
@@ -179,7 +259,7 @@ protected void login()
179259 // docs:
180260 // https://docs.easydb.de/en/technical/api/eas/
181261 // https://docs.easydb.de/en/sysadmin/eas/api/put/
182- String baseQueryUrl = this . url + "eas/put?token=" + this . token ;
262+ String baseQueryUrl = buildAuthenticatedUrl ( "eas/put" ) ;
183263 ArrayList <JSONObject > results = new ArrayList <>();
184264 HashMap <String , JSONObject > existingFilenames = new HashMap <>();
185265 if (existingExport != null &&
@@ -274,7 +354,7 @@ public JSONObject createObjectInNahima(JSONObject object, String objType)
274354 throws IOException , InterruptedException {
275355 // docs:
276356 // https://docs.easydb.de/en/technical/api/db/
277- String queryURL = this . url + "db/" + objType + "?token=" + token ;
357+ String queryURL = buildAuthenticatedUrl ( "db/" + objType ) ;
278358 // EasyDB seems to have mixed up PUT & POST, but well, we don't care
279359 String returnValue = this .putRequest (
280360 queryURL , (new JSONArray ()).put (object ).toString (), new HashMap <>() {
@@ -308,7 +388,7 @@ public JSONObject createObjectInNahima(JSONObject object, String objType)
308388 }
309389
310390 public JSONObject findObjectByUuid (String uuid ) throws IOException {
311- String queryURL = this . url + "objects/uuid/" + uuid + "?token=" + token ;
391+ String queryURL = buildAuthenticatedUrl ( "objects/uuid/" + uuid ) ;
312392 String returnValue = this .getRequest (queryURL , new HashMap <>() {
313393 {
314394 put ("Content-Type" , "application/json" );
@@ -343,8 +423,7 @@ public JSONObject findObjectByGlobalObjectId(String globalObjectId)
343423 return null ;
344424 }
345425
346- String queryURL = this .url + "search"
347- + "?token=" + token ;
426+ String queryURL = buildAuthenticatedUrl ("search" );
348427 JSONObject query = new JSONObject () {
349428 {
350429 put ("best_mask_filter" , true );
@@ -449,8 +528,7 @@ public JSONObject searchByString(String searchString,
449528 }
450529
451530 // load fresh
452- String queryURL = this .url + "search"
453- + "?token=" + token ;
531+ String queryURL = buildAuthenticatedUrl ("search" );
454532 JSONArray search = new JSONArray ();
455533
456534 String [] splitName = searchString .split (" " );
@@ -1303,7 +1381,7 @@ public JSONObject resolveCountry(String countryName, String isoCountryCode)
13031381 query .put ("objecttypes" , new JSONArray ().put ("gazetteer" ));
13041382
13051383 // Execute the search
1306- String queryURL = this . url + "search?token=" + token ;
1384+ String queryURL = buildAuthenticatedUrl ( "search" ) ;
13071385 JSONObject result = this .postRequest (queryURL , query );
13081386
13091387 if (result .has ("code" ) && result .getString ("code" ).startsWith ("error" )) {
@@ -2048,7 +2126,7 @@ public JSONObject findTagWithName(String name) throws IOException {
20482126 return tagFromCache ;
20492127 }
20502128
2051- String queryUrl = this . url + "tags?token=" + this . token ;
2129+ String queryUrl = buildAuthenticatedUrl ( "tags" ) ;
20522130
20532131 String response = this .getRequest (queryUrl );
20542132 if (!response .startsWith ("[" )) {
0 commit comments