Skip to content

Commit 6e344c1

Browse files
author
Chris Wiechmann
committed
Fix: Cache update implemented
#253
1 parent 38e7367 commit 6e344c1

8 files changed

Lines changed: 92 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1919
- Backslashes in user passwords are ignored (See issue [#244](https://github.com/Axway-API-Management-Plus/apim-cli/issues/244))
2020

2121
### Added
22-
- Added updateOnly toggle (See issue [#251](https://github.com/Axway-API-Management-Plus/apim-cli/issues/251))
23-
- Added support to delete applications from API-Manager
24-
- Added support for API-Method level quotas
22+
- Support to use a cache for import actions (See issue [#253](https://github.com/Axway-API-Management-Plus/apim-cli/issues/253))
23+
- UpdateOnly toggle (See issue [#251](https://github.com/Axway-API-Management-Plus/apim-cli/issues/251))
24+
- Support to delete applications from API-Manager
25+
- Support for API-Method level quotas
2526

2627
## [1.6.1] 2021-12-20
2728

modules/apim-adapter/src/main/java/com/axway/apim/adapter/APIManagerAdapter.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public class APIManagerAdapter {
104104

105105
private static CoreParameters cmd;
106106

107-
private static FilteredCacheManager cacheManager;
107+
public static FilteredCacheManager cacheManager;
108108

109109
public APIManagerConfigAdapter configAdapter;
110110
public APIManagerCustomPropertiesAdapter customPropertiesAdapter;
@@ -126,10 +126,20 @@ public static enum CacheType {
126126
oauthClientProviderCache,
127127
applicationsCache,
128128
applicationsSubscriptionCache,
129-
applicationsQuotaCache,
129+
applicationsQuotaCache(true),
130130
applicationsCredentialCache,
131131
organizationCache,
132132
userCache;
133+
134+
public boolean supportsImportActions = false;
135+
136+
private CacheType() {
137+
this.supportsImportActions = false;
138+
}
139+
140+
private CacheType(boolean supportsImportActions) {
141+
this.supportsImportActions = supportsImportActions;
142+
}
133143
}
134144

135145
public static synchronized APIManagerAdapter getInstance() throws AppException {
@@ -149,9 +159,9 @@ public static synchronized APIManagerAdapter getInstance() throws AppException {
149159

150160
public static synchronized void deleteInstance() throws AppException {
151161
if(APIManagerAdapter.cacheManager!=null && APIManagerAdapter.cacheManager.getStatus()==Status.AVAILABLE) {
152-
LOG.debug("Closing cache begin");
162+
LOG.debug("Closing cache ...");
153163
APIManagerAdapter.cacheManager.close();
154-
LOG.debug("Closing cache end");
164+
LOG.trace("Cache Closed.");
155165
}
156166
if(APIManagerAdapter.instance!=null) {
157167
if(hasOrgAdmin()) APIManagerAdapter.instance.logoutFromAPIManager(false); // Logout potentially logged in OrgAdmin

modules/apim-adapter/src/main/java/com/axway/apim/adapter/apis/APIManagerAPIAccessAdapter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public List<APIAccess> getAPIAccess(AbstractEntity entity, Type type, boolean in
120120
for(APIAccess apiAccess : allApiAccess) {
121121
API api = APIManagerAdapter.getInstance().apiAdapter.getAPI(new APIFilter.Builder().hasId(apiAccess.getApiId()).build(), false);
122122
if(api==null) {
123-
throw new AppException("Unable to find API with ID: " + apiAccess.getApiId() + " referenced by "+type.niceName+": " + entity.getName(), ErrorCode.UNKNOWN_API);
123+
throw new AppException("Unable to find API with ID: " + apiAccess.getApiId() + " referenced by "+type.niceName+": " + entity.getName() + ". You may try again with -clearCache", ErrorCode.UNKNOWN_API);
124124
}
125125
apiAccess.setApiName(api.getName());
126126
apiAccess.setApiVersion(api.getVersion());

modules/apim-adapter/src/main/java/com/axway/apim/adapter/apis/APIManagerConfigAdapter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ private void readConfigFromAPIManager(boolean useAdmin) throws AppException {
9090
HttpResponse httpResponse = null;
9191
try {
9292
uri = new URIBuilder(cmd.getAPIManagerURL()).setPath(cmd.getApiBasepath() + "/config").build();
93-
LOG.debug("Load configuration API-Manager.");
93+
LOG.debug("Load API-Manager configuration.");
9494
RestAPICall getRequest = new GETRequest(uri, useAdmin);
9595
httpResponse = getRequest.execute();
9696
String response = EntityUtils.toString(httpResponse.getEntity());

modules/apim-adapter/src/main/java/com/axway/apim/adapter/clientApps/APIMgrAppsAdapter.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,14 @@ public class APIMgrAppsAdapter {
7070
Cache<String, String> applicationsCache;
7171
Cache<String, String> applicationsSubscriptionCache;
7272
Cache<String, String> applicationsCredentialCache;
73+
Cache<String, String> applicationsQuotaCache;
7374

7475
public APIMgrAppsAdapter() throws AppException {
7576
applicationsCache = APIManagerAdapter.getCache(CacheType.applicationsCache, String.class, String.class);
7677
applicationsSubscriptionCache = APIManagerAdapter.getCache(CacheType.applicationsSubscriptionCache, String.class, String.class);
7778
applicationsCredentialCache = APIManagerAdapter.getCache(CacheType.applicationsCredentialCache, String.class, String.class);
79+
// Must be refactored to use Quota-Adapter instead of doing this in
80+
applicationsQuotaCache = APIManagerAdapter.getCache(CacheType.applicationsQuotaCache, String.class, String.class);
7881
}
7982

8083
/**
@@ -352,10 +355,6 @@ void addImage(ClientApplication app, boolean addImage) throws Exception {
352355
app.setImage(image);
353356
}
354357

355-
void addQuota(ClientApplication app, boolean addQuota) {
356-
357-
}
358-
359358
public ClientApplication updateApplication(ClientApplication desiredApp, ClientApplication actualApp) throws AppException {
360359
return createOrUpdateApplication(desiredApp, actualApp);
361360
}
@@ -594,6 +593,8 @@ private void saveQuota(ClientApplication app, ClientApplication actualApp) throw
594593
LOG.error("Error creating/updating application quota. Response-Code: "+statusCode+". Got response: '"+EntityUtils.toString(httpResponse.getEntity())+"'");
595594
throw new AppException("Error creating application' Response-Code: "+statusCode+"", ErrorCode.API_MANAGER_COMMUNICATION);
596595
}
596+
// Force reload of this quota next time
597+
applicationsQuotaCache.remove(app.getId());
597598
} catch (Exception e) {
598599
throw new AppException("Error creating application quota. Error: " + e.getMessage(), ErrorCode.CANT_CREATE_API_PROXY, e);
599600
} finally {

modules/apim-adapter/src/main/java/com/axway/apim/lib/FilteredCacheManager.java

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,16 @@
1313
import org.slf4j.Logger;
1414
import org.slf4j.LoggerFactory;
1515

16+
import com.axway.apim.adapter.APIManagerAdapter;
1617
import com.axway.apim.adapter.APIManagerAdapter.CacheType;
18+
import com.axway.apim.lib.DoNothingCacheManager.DoNothingCache;
19+
import com.axway.apim.lib.errorHandling.AppException;
20+
import com.axway.apim.lib.errorHandling.ErrorCode;
21+
import com.fasterxml.jackson.databind.JsonNode;
22+
import com.fasterxml.jackson.databind.ObjectMapper;
23+
import com.fasterxml.jackson.databind.node.ArrayNode;
24+
import com.fasterxml.jackson.databind.node.ObjectNode;
25+
import com.fasterxml.jackson.databind.node.TextNode;
1726

1827
public class FilteredCacheManager implements CacheManager {
1928

@@ -37,7 +46,11 @@ public void setEnabledCaches(List<CacheType> enabledCaches) {
3746
if(enabledCaches==null || cacheManager instanceof DoNothingCacheManager) return;
3847
this.enabledCaches = new ArrayList<String>();
3948
for(CacheType cacheType : enabledCaches) {
40-
this.enabledCaches.add(cacheType.name());
49+
if(cacheType.supportsImportActions) {
50+
this.enabledCaches.add(cacheType.name());
51+
} else {
52+
LOG.error("The cache: " + cacheType.name() + " is currently not supported for import actions.");
53+
}
4154
}
4255
LOG.info("Enabled caches: " + this.enabledCaches);
4356
}
@@ -95,5 +108,46 @@ public void removeCache(String arg0) {
95108
cacheManager.removeCache(arg0);
96109
}
97110

98-
111+
/**
112+
* There are a number of entities which have references to an API (e.g. QuotaRestrictions).
113+
* These are stored/maintained with their own ID (quotaId) and cached in Ehcache.
114+
* But, if the API-ID changes, the cached reference points to an API that no longer exists.
115+
* This method is used to update all entities in the cache when the API ID of an API
116+
* changes (e.g. with a Replace Action).
117+
* @param oldApiId the ID currently used by the cached entities
118+
* @param newApiId the new ID that must be replaced
119+
* @throws AppException when the cache cannot be updated.
120+
*/
121+
public void flipApiId(String oldApiId, String newApiId) throws AppException {
122+
ObjectMapper mapper = new ObjectMapper();
123+
Cache<String, String> appQuotaCached = getCache(CacheType.applicationsQuotaCache.name(), String.class, String.class);
124+
if(appQuotaCached instanceof DoNothingCache) return;
125+
LOG.debug("Updating ApplicationQuotaCache: Flip API-ID: " + oldApiId + " --> " + newApiId);
126+
try {
127+
appQuotaCached.forEach(entry -> {
128+
try {
129+
String cachedValueString = entry.getValue();
130+
JsonNode cachedValue = mapper.readTree(cachedValueString);
131+
// As System- and App-Default-Quotas are not cached, they can be ignored
132+
if(APIManagerAdapter.APPLICATION_DEFAULT_QUOTA.equals(cachedValue.get("id").asText()) ||
133+
APIManagerAdapter.SYSTEM_API_QUOTA.equals(cachedValue.get("id").asText())) {
134+
// Do nothing
135+
} else {
136+
ArrayNode restrictions = cachedValue.withArray("restrictions");
137+
for(JsonNode restriction : restrictions) {
138+
if(oldApiId.equals(restriction.get("api").asText())) {
139+
((ObjectNode)restriction).replace("api", new TextNode(newApiId));
140+
appQuotaCached.replace(entry.getKey(), cachedValue.toString());
141+
}
142+
}
143+
}
144+
} catch (Exception e) {
145+
throw new RuntimeException("There was an error updating the cache.", e);
146+
}
147+
});
148+
} catch (Exception e) {
149+
appQuotaCached.clear();
150+
throw new AppException("Error updating the cache. Cache has been cleared.", ErrorCode.UNXPECTED_ERROR, e);
151+
}
152+
}
99153
}

modules/apis/src/main/java/com/axway/apim/apiimport/actions/CreateNewAPI.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@
2323
public class CreateNewAPI {
2424

2525
static Logger LOG = LoggerFactory.getLogger(CreateNewAPI.class);
26+
27+
private API createdAPI = null;
2628

2729
public void execute(APIChangeState changes, boolean reCreation) throws AppException {
2830

29-
API createdAPI = null;
3031
API desiredAPI = changes.getDesiredAPI();
3132
API actualAPI = changes.getActualAPI();
3233

@@ -91,4 +92,8 @@ public void execute(APIChangeState changes, boolean reCreation) throws AppExcept
9192
}
9293
}
9394
}
95+
96+
public API getCreatedAPI() {
97+
return createdAPI;
98+
}
9499
}

modules/apis/src/main/java/com/axway/apim/apiimport/actions/RecreateToUpdateAPI.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import org.slf4j.Logger;
44
import org.slf4j.LoggerFactory;
55

6+
import com.axway.apim.adapter.APIManagerAdapter;
67
import com.axway.apim.adapter.APIStatusManager;
78
import com.axway.apim.api.API;
89
import com.axway.apim.apiimport.APIChangeState;
@@ -37,6 +38,10 @@ public void execute(APIChangeState changes) throws AppException {
3738
LOG.info("New API successfuly created. Going to delete old API: '"+actualAPI.getName()+"' "+actualAPI.getVersion()+" (ID: "+actualAPI.getId()+")");
3839
// Delete the existing old API!
3940
new APIStatusManager().update(actualAPI, API.STATE_DELETED, true);
41+
42+
// Maintain the Ehcache
43+
// All cached entities referencing this API must be updated with the correct API-ID
44+
APIManagerAdapter.cacheManager.flipApiId(changes.getActualAPI().getId(), createNewAPI.getCreatedAPI().getId());
4045
}
4146

4247
}

0 commit comments

Comments
 (0)