286 lines
10 KiB
Java
286 lines
10 KiB
Java
/*
|
|
* Copyright 2015 Trento Rise.
|
|
*
|
|
* Licensed 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.gcube.datacatalogue.utillibrary.jackan;
|
|
|
|
import static com.google.common.base.Preconditions.checkNotNull;
|
|
import static org.gcube.datacatalogue.utillibrary.server.utils.GenericUtils.checkNotEmpty;
|
|
import static org.gcube.datacatalogue.utillibrary.server.utils.GenericUtils.isNotEmpty;
|
|
|
|
import java.net.MalformedURLException;
|
|
import java.net.URISyntaxException;
|
|
import java.net.URL;
|
|
import java.util.List;
|
|
import java.util.UUID;
|
|
|
|
import javax.annotation.Nullable;
|
|
|
|
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanDataset;
|
|
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanDatasetBase;
|
|
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanGroup;
|
|
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanLicense;
|
|
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanOrganization;
|
|
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanResource;
|
|
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanResourceBase;
|
|
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.exceptions.CkanNotFoundException;
|
|
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.exceptions.CkanValidationException;
|
|
|
|
/**
|
|
* This client performs additional checks when writing to CKAN to ensure written
|
|
* content is correct. For this reason it might do additional calls and results
|
|
* of validation might be different from default Ckan ones. But if Ckan actually
|
|
* performed all the checks it should do there wouldn't be any need of this
|
|
* class as well..
|
|
*
|
|
* <p>
|
|
* Note: For {@code create} operations, this client fails if item is already
|
|
* existing on the server. This behaviour is different from ckan default
|
|
* {@code upsert} behaviour (update an existing) to prevent misuse.
|
|
* </p>
|
|
*
|
|
* @author David Leoni
|
|
* @since 0.4.1
|
|
*/
|
|
public class CheckedCkanClient extends CkanClient {
|
|
|
|
protected CheckedCkanClient() {
|
|
super();
|
|
}
|
|
|
|
protected CheckedCkanClient(String url) {
|
|
super(url);
|
|
}
|
|
|
|
public CheckedCkanClient(String catalogUrl, @Nullable String ckanToken) {
|
|
super(catalogUrl, ckanToken);
|
|
}
|
|
|
|
/**
|
|
* Returns a builder instance. The builder is not threadsafe and you can use
|
|
* one builder instance to build only one client instance.
|
|
*/
|
|
public static CkanClient.Builder builder() {
|
|
return CkanClient.newBuilder(new CheckedCkanClient());
|
|
}
|
|
|
|
private void checkUrl(String url, String prependedErrorMessage) {
|
|
try {
|
|
new URL(url).toURI();
|
|
} catch (MalformedURLException | URISyntaxException ex) {
|
|
throw new CkanValidationException(String.valueOf(prependedErrorMessage) + " -- Ill-formed url:" + url, this,
|
|
ex);
|
|
}
|
|
}
|
|
|
|
private void checkUuid(String uuid, String prependedErrorMessage) {
|
|
try {
|
|
UUID.fromString(uuid);
|
|
} catch (Exception ex) {
|
|
throw new CkanValidationException(String.valueOf(prependedErrorMessage) + " -- Ill-formed uuid:" + uuid,
|
|
this, ex);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*
|
|
* <p>
|
|
* NOTE: In CheckedCkanClient {@code create} operations fail if item already
|
|
* exists. This is different from Ckan default behaviour, which updates
|
|
* items if they already exist.
|
|
* </p>
|
|
*/
|
|
@Override
|
|
public synchronized CkanOrganization createOrganization(CkanOrganization org) {
|
|
if (org.getId() != null) {
|
|
|
|
checkUuid(org.getId(),
|
|
"Jackan validation failed! Tried to create organization with invalid id:" + org.getId());
|
|
|
|
try {
|
|
getOrganization(org.getId());
|
|
throw new CkanValidationException(
|
|
"Jackan validation failed! Tried to create organization with existing id! " + org.getId(),
|
|
this);
|
|
} catch (CkanNotFoundException ex) {
|
|
|
|
}
|
|
}
|
|
|
|
return super.createOrganization(org);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*
|
|
* <p>
|
|
* NOTE: In CheckedCkanClient {@code create} operations fail if item already
|
|
* exists. This is different from Ckan default behaviour, which updates
|
|
* items if they already exist.
|
|
* </p>
|
|
*/
|
|
@Override
|
|
public synchronized CkanResource createResource(CkanResourceBase resource) {
|
|
|
|
if (resource.getId() != null) {
|
|
checkUuid(resource.getId(),
|
|
"Jackan validation failed! Tried to create resource with invalid id:" + resource.getId());
|
|
|
|
try {
|
|
getResource(resource.getId());
|
|
throw new CkanValidationException(
|
|
"Jackan validation failed! Tried to create resource with existing id! " + resource.getId(),
|
|
this);
|
|
} catch (CkanNotFoundException ex) {
|
|
|
|
}
|
|
}
|
|
|
|
// Only check for URL if no file is given
|
|
// If a file is given, the URL field is statically set to "upload"
|
|
if (resource.getUpload() == null)
|
|
checkUrl(resource.getUrl(),
|
|
"Jackan validation error! Tried to create resource " + resource.getId() + " with wrong url!");
|
|
|
|
return super.createResource(resource);
|
|
}
|
|
|
|
@Override
|
|
public synchronized CkanResource updateResource(CkanResourceBase resource) {
|
|
|
|
checkUrl(resource.getUrl(),
|
|
"Jackan validation error! Tried to update resource " + resource.getId() + " with wrong url!");
|
|
|
|
return super.updateResource(resource);
|
|
}
|
|
|
|
@Override
|
|
public synchronized CkanResource patchUpdateResource(CkanResourceBase resource) {
|
|
|
|
checkUrl(resource.getUrl(),
|
|
"Jackan validation error! Tried to patch update resource " + resource.getId() + " with wrong url!");
|
|
|
|
return super.patchUpdateResource(resource);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*
|
|
* <p>
|
|
* NOTE: In CheckedCkanClient {@code create} operations fail if item already
|
|
* exists. This is different from Ckan default behaviour, which updates
|
|
* items if they already exist.
|
|
* </p>
|
|
*/
|
|
@Override
|
|
public synchronized CkanGroup createGroup(CkanGroup group) {
|
|
|
|
if (group.getId() != null) {
|
|
|
|
checkUuid(group.getId(),
|
|
"Jackan validation failed! Tried to create group with invalid id:" + group.getId());
|
|
|
|
try {
|
|
getGroup(group.getId());
|
|
throw new CkanValidationException(
|
|
"Jackan validation failed! Tried to create group with existing id! " + group.getId(), this);
|
|
} catch (CkanNotFoundException ex) {
|
|
|
|
}
|
|
}
|
|
|
|
return super.createGroup(group);
|
|
}
|
|
|
|
private void checkGroupsExist(Iterable<CkanGroup> groups, String prependedErrorMessage) {
|
|
if (groups != null) {
|
|
for (CkanGroup group : groups) {
|
|
checkNotNull(group, String.valueOf(prependedErrorMessage) + " -- Found null group! ");
|
|
checkNotEmpty(group.idOrName(),
|
|
String.valueOf(prependedErrorMessage) + " -- Found group with both id and name invalid!");
|
|
|
|
try {
|
|
getGroup(group.idOrName());
|
|
} catch (CkanNotFoundException ex) {
|
|
throw new CkanValidationException(
|
|
prependedErrorMessage + " -- Tried to refer to non existing group " + group.idOrName(),
|
|
this, ex);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
private void checkLicenseExist(@Nullable String licenseId, String prependedErrorMessage) {
|
|
if (isNotEmpty(licenseId)) {
|
|
List<CkanLicense> licenseList = getLicenseList();
|
|
boolean found = false;
|
|
for (CkanLicense lic : licenseList) {
|
|
if (licenseId.equals(lic.getId())) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
throw new CkanValidationException(String.valueOf(prependedErrorMessage) + " -- licenseId '" + licenseId
|
|
+ "' doesn't belong to allowed licenses: " + licenseList.toString(), this);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*
|
|
* <p>
|
|
* NOTE: In CheckedCkanClient {@code create} operations fail if item already
|
|
* exists. This is different from Ckan default behaviour, which updates
|
|
* items if they already exist.
|
|
* </p>
|
|
*/
|
|
@Override
|
|
public synchronized CkanDataset createDataset(CkanDatasetBase dataset) {
|
|
|
|
checkGroupsExist(dataset.getGroups(), "Jackan validation error when creating dataset " + dataset.getName());
|
|
|
|
checkLicenseExist(dataset.getLicenseId(), "Jackan validation error when creating dataset " + dataset.getName());
|
|
|
|
return super.createDataset(dataset);
|
|
}
|
|
|
|
@Override
|
|
public synchronized CkanDataset updateDataset(CkanDatasetBase dataset) {
|
|
|
|
checkGroupsExist(dataset.getGroups(), "Jackan validation error when updating dataset " + dataset.getName());
|
|
|
|
checkLicenseExist(dataset.getLicenseId(), "Jackan validation error updating dataset " + dataset.getName());
|
|
|
|
return super.updateDataset(dataset);
|
|
}
|
|
|
|
@Override
|
|
public synchronized CkanDataset patchUpdateDataset(CkanDatasetBase dataset) {
|
|
|
|
checkGroupsExist(dataset.getGroups(),
|
|
"Jackan validation error when patch updating dataset " + dataset.getName());
|
|
|
|
checkLicenseExist(dataset.getLicenseId(),
|
|
"Jackan validation error when patch updating dataset " + dataset.getName());
|
|
|
|
return super.patchUpdateDataset(dataset);
|
|
}
|
|
|
|
}
|