blob: 2dcf0d72499b0f254f1ca7dabe8c0ffc9a205ce4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.sling.feature.extension.apiregions.api;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonArrayBuilder;
import javax.json.JsonException;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.json.JsonReader;
import javax.json.JsonString;
import javax.json.JsonValue;
import javax.json.JsonValue.ValueType;
import javax.json.JsonWriter;
import org.apache.sling.feature.ArtifactId;
/**
* An api regions configuration
*/
public class ApiRegions {
/** The name of the api regions extension. */
public static final String EXTENSION_NAME = "api-regions";
private static final String NAME_KEY = "name";
private static final String EXPORTS_KEY = "exports";
private static final String TOGGLE_KEY = "toggle";
private static final String PREVIOUS_KEY = "previous";
private final List<ApiRegion> regions = new ArrayList<>();
public List<ApiRegion> getRegions() {
return this.regions;
}
/**
* Add the region. The region is only added if there isn't already a region with
* the same name
*
* @param region The region to add
* @return {@code true} if the region could be added, {@code false} otherwise
*/
public boolean addUniqueRegion(final ApiRegion region) {
boolean found = false;
for (final ApiRegion c : this.regions) {
if (c.getName().equals(region.getName())) {
found = true;
break;
}
}
if (!found) {
this.regions.add(region);
}
return !found;
}
/**
* Get a named region
*
* @param name The name
* @return The region or {@code null}
*/
public ApiRegion getRegionByName(final String name) {
ApiRegion found = null;
for (final ApiRegion c : this.regions) {
if (c.getName().equals(name)) {
found = c;
break;
}
}
return found;
}
/**
* Get the names of the regions
*
* @return The list of regions, might be empty
*/
public List<String> getRegionNames() {
final List<String> names = new ArrayList<>();
for (final ApiRegion c : this.regions) {
names.add(c.getName());
}
return Collections.unmodifiableList(names);
}
/**
* Convert regions into json
*
* @return The json array
* @throws IOException If generating the JSON fails
*/
public JsonArray toJSONArray() throws IOException {
final JsonArrayBuilder arrayBuilder = Json.createArrayBuilder();
for (final ApiRegion region : this.getRegions()) {
final JsonObjectBuilder regionBuilder = Json.createObjectBuilder();
regionBuilder.add(NAME_KEY, region.getName());
if (!region.getExports().isEmpty()) {
final JsonArrayBuilder expArrayBuilder = Json.createArrayBuilder();
for (final ApiExport exp : region.getExports()) {
if (exp.getToggle() == null) {
expArrayBuilder.add(exp.getName());
} else {
final JsonObjectBuilder expBuilder = Json.createObjectBuilder();
expBuilder.add(NAME_KEY, exp.getName());
expBuilder.add(TOGGLE_KEY, exp.getToggle());
if (exp.getPrevious() != null) {
expBuilder.add(PREVIOUS_KEY, exp.getPrevious().toMvnId());
}
expArrayBuilder.add(expBuilder);
}
}
regionBuilder.add(EXPORTS_KEY, expArrayBuilder);
}
for (final Map.Entry<String, String> entry : region.getProperties().entrySet()) {
regionBuilder.add(entry.getKey(), entry.getValue());
}
arrayBuilder.add(regionBuilder);
}
return arrayBuilder.build();
}
/**
* Convert regions into json
*
* @return The json array as a string
* @throws IOException If generating the JSON fails
*/
public String toJSON() throws IOException {
final JsonArray array = this.toJSONArray();
try (final StringWriter stringWriter = new StringWriter();
final JsonWriter writer = Json.createWriter(stringWriter)) {
writer.writeArray(array);
return stringWriter.toString();
}
}
/**
* Parse a JSON array into an api regions object
*
* @param json The json as a string
* @return The api regions
* @throws IOException If the json could not be parsed
*/
public static ApiRegions parse(final String json) throws IOException {
try (final JsonReader reader = Json.createReader(new StringReader(json))) {
return parse(reader.readArray());
}
}
/**
* Parse a JSON array into an api regions object
*
* @param json The json
* @return The api regions
* @throws IOException If the json could not be parsed
*/
public static ApiRegions parse(final JsonArray json) throws IOException {
try {
final ApiRegions regions = new ApiRegions();
for (final JsonValue value : json) {
if (value.getValueType() != ValueType.OBJECT) {
throw new IOException("Illegal api regions json " + json);
}
final ApiRegion region = new ApiRegion();
final JsonObject obj = (JsonObject) value;
region.setName(obj.getString(NAME_KEY));
for (final Map.Entry<String, JsonValue> entry : obj.entrySet()) {
if (NAME_KEY.equals(entry.getKey())) {
region.setName(obj.getString(NAME_KEY));
} else if (entry.getKey().equals(EXPORTS_KEY)) {
for (final JsonValue e : (JsonArray) entry.getValue()) {
if (e.getValueType() == ValueType.STRING) {
final String name = ((JsonString) e).getString();
if (!name.startsWith("#")) {
final ApiExport export = new ApiExport();
region.getExports().add(export);
export.setName(name);
}
} else if (e.getValueType() == ValueType.OBJECT) {
final JsonObject expObj = (JsonObject) e;
final ApiExport export = new ApiExport();
region.getExports().add(export);
export.setName(expObj.getString(NAME_KEY));
export.setToggle(expObj.getString(TOGGLE_KEY, null));
if (expObj.containsKey(PREVIOUS_KEY)) {
export.setPrevious(ArtifactId.parse(expObj.getString(PREVIOUS_KEY)));
}
}
}
} else {
region.getProperties().put(entry.getKey(), ((JsonString) entry.getValue()).getString());
}
}
if (!regions.addUniqueRegion(region)) {
throw new IOException("Region " + region.getName() + " is defined twice");
}
}
return regions;
} catch (final JsonException | IllegalArgumentException e) {
throw new IOException(e);
}
}
@Override
public String toString() {
return "ApiRegions [regions=" + regions + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((regions == null) ? 0 : regions.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ApiRegions other = (ApiRegions) obj;
if (regions == null) {
if (other.regions != null)
return false;
} else if (!regions.equals(other.regions))
return false;
return true;
}
}