All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.erudika.para.core.App Maven / Gradle / Ivy

There is a newer version: 1.50.3
Show newest version
/*
 * Copyright 2013-2017 Erudika. https://erudika.com
 *
 * 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.
 *
 * For issues and patches go to: https://github.com/erudika
 */
package com.erudika.para.core;

import com.erudika.para.core.utils.CoreUtils;
import com.erudika.para.core.utils.ParaObjectUtils;
import com.erudika.para.annotations.Locked;
import com.erudika.para.annotations.Stored;
import static com.erudika.para.core.App.AllowedMethods.ALL;
import static com.erudika.para.core.App.AllowedMethods.GET;
import static com.erudika.para.core.App.AllowedMethods.GUEST;
import static com.erudika.para.core.App.AllowedMethods.READ_AND_WRITE;
import static com.erudika.para.core.App.AllowedMethods.READ_ONLY;
import static com.erudika.para.core.App.AllowedMethods.READ_WRITE;
import static com.erudika.para.core.App.AllowedMethods.WRITE_ONLY;
import static com.erudika.para.core.App.AllowedMethods.fromString;
import com.erudika.para.utils.Config;
import com.erudika.para.utils.Pager;
import com.erudika.para.utils.Utils;
import com.erudika.para.validation.Constraint;
import com.erudika.para.validation.ValidationUtils;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonValue;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.apache.commons.collections.bidimap.DualHashBidiMap;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.constraints.NotBlank;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This is a representation of an application within Para.
 * 
* It allows the user to create separate apps running on the same infrastructure. * Every {@link ParaObject} belongs to an app. *
* Apps can have a dedicated table or they can share the same table using prefixed keys. * Also, apps can have a dedicated search index or share one. These are controlled by * the two flags {@link #isSharingTable() } and {@link #isSharingIndex() }. *
* Usually when we have a multi-app environment there's a parent app (dedicated) and * lots of child apps (shared) that share the same index with the parent app. * * @author Alex Bogdanovski [[email protected]] */ public class App implements ParaObject, Serializable { /** * {@value #APP_ROLE}. */ public static final String APP_ROLE = "ROLE_APP"; /** * {@value #ALLOW_ALL}. */ public static final String ALLOW_ALL = "*"; private static final long serialVersionUID = 1L; private static final String PREFIX = Utils.type(App.class).concat(Config.SEPARATOR); private static final Logger logger = LoggerFactory.getLogger(App.class); @Stored @Locked @NotBlank private String id; @Stored @Locked private Long timestamp; @Stored @Locked private String type; @Stored @Locked private String appid; @Stored @Locked private String parentid; @Stored @Locked private String creatorid; @Stored private Long updated; @Stored private String name; @Stored private List tags; @Stored private Integer votes; @Stored private Boolean stored; @Stored private Boolean indexed; @Stored private Boolean cached; @Stored @Locked private boolean sharingIndex; @Stored @Locked private boolean sharingTable; @Stored @Locked private String secret; @Stored @Locked private Boolean readOnly; @Stored private Map datatypes; // type -> field -> constraint -> property -> value @Stored private Map>>> validationConstraints; // subject_id -> resource_name -> [http_methods_allowed] @Stored private Map>> resourcePermissions; @Stored private Boolean active; @Stored private Long deleteOn; @Stored private Long tokenValiditySec; // used to store various settings, OAuth keys, etc. @Stored private Map settings; /** * No-args constructor. */ public App() { this(null); } /** * Default constructor. * @param id the name of the app */ public App(String id) { this.sharingIndex = true; this.sharingTable = false; this.active = true; this.readOnly = false; setId(id); setName(getName()); } /** * Returns the correct id of this app with prefix. * @param id an id like "myapp" * @return the full id, e.g. "app:myapp" */ public static final String id(String id) { if (StringUtils.startsWith(id, PREFIX)) { return PREFIX.concat(Utils.noSpaces(Utils.stripAndTrim(id.replaceAll(PREFIX, ""), " "), "-")); } else if (id != null) { return PREFIX.concat(Utils.noSpaces(Utils.stripAndTrim(id, " "), "-")); } else { return null; } } @Override public final void setId(String id) { this.id = id(id); } /** * Adds a new setting to the map. * @param name a key * @param value a value * @return this */ public App addSetting(String name, Object value) { if (!StringUtils.isBlank(name) && value != null) { getSettings().put(name, value); } return this; } /** * Returns the value of a setting for a given key. * @param name the key * @return the value */ public Object getSetting(String name) { if (!StringUtils.isBlank(name)) { return getSettings().get(name); } return null; } /** * Removes a setting from the map. * @param name the key * @return this */ public App removeSetting(String name) { if (!StringUtils.isBlank(name)) { getSettings().remove(name); } return this; } /** * A map of all settings (key/values). * @return a map */ @JsonIgnore public Map getSettings() { if (settings == null) { settings = new HashMap(); } return settings; } /** * Overwrites the settings map. * @param settings a new map */ public void setSettings(Map settings) { this.settings = settings; } /** * Returns a map of user-defined data types and their validation annotations. * @return the constraints map */ public Map>>> getValidationConstraints() { if (validationConstraints == null) { validationConstraints = new HashMap>>>(); } return validationConstraints; } /** * Sets the validation constraints map. * @param validationConstraints the constraints map */ public void setValidationConstraints(Map>>> validationConstraints) { this.validationConstraints = validationConstraints; } /** * Returns a map of resource permissions. * @return the permissions map */ public Map>> getResourcePermissions() { if (resourcePermissions == null) { resourcePermissions = new HashMap>>(); } return resourcePermissions; } /** * Sets the permissions map. * @param resourcePermissions permissions map */ public void setResourcePermissions(Map>> resourcePermissions) { this.resourcePermissions = resourcePermissions; } /** * The App identifier (the id but without the prefix 'app:'). * The identifier may start with a whitespace character e.g. " myapp". * This indicates that the app is sharing a table with other apps. * This is disabled by default unless 'para.prepend_shared_appids_with_space = true' * @return the identifier (appid) */ public String getAppIdentifier() { String pre = isSharingTable() && Config.getConfigBoolean("prepend_shared_appids_with_space", false) ? " " : ""; return (getId() != null) ? getId().replaceFirst(PREFIX, pre) : ""; } /** * Returns true if this application is active (enabled). * @return true if active */ public Boolean getActive() { return active; } /** * Sets the active flag. When an app is disabled (active = false) * it cannot be accessed through the API. * @param active true if active */ public void setActive(Boolean active) { this.active = active; } /** * The timestamp for when this app must be deleted. * @return a timestamp */ public Long getDeleteOn() { return deleteOn; } /** * Sets the time for deletion. * @param deleteOn a timestamp */ public void setDeleteOn(Long deleteOn) { this.deleteOn = deleteOn; } /** * The validity period for access tokens in seconds. * This setting is for current app only. * Always returns a default value if local setting is null. * @return period in seconds */ public Long getTokenValiditySec() { if (tokenValiditySec == null || tokenValiditySec <= 0) { tokenValiditySec = Config.JWT_EXPIRES_AFTER_SEC; } return tokenValiditySec; } /** * Sets the access token validity period in seconds. * @param tokenValiditySec seconds */ public void setTokenValiditySec(Long tokenValiditySec) { if (tokenValiditySec == null || tokenValiditySec <= 0) { this.tokenValiditySec = 0L; } this.tokenValiditySec = tokenValiditySec; } /** * Returns the app's secret key. * @return the secret key */ @JsonIgnore public String getSecret() { return secret; } /** * Sets the secret key. * @param secret a secret key */ public void setSecret(String secret) { this.secret = secret; } /** * Gets read-only mode. * @return true if app is in read-only mode */ public Boolean getReadOnly() { return readOnly; } /** * Sets read-only mode. * @param readOnly true if app is in read-only mode */ public void setReadOnly(Boolean readOnly) { this.readOnly = readOnly; } /** * Returns a set of custom data types for this app. * An app can have many custom types which describe its domain. * @return a map of type names (plural form to singular) */ @SuppressWarnings("unchecked") public Map getDatatypes() { if (datatypes == null) { datatypes = new DualHashBidiMap(); } return datatypes; } /** * Sets the data types for this app. * @param datatypes a map of type names (plural form to singular) */ public void setDatatypes(Map datatypes) { this.datatypes = datatypes; } /** * Is this a sharing the search index with other apps. * @return true if it does */ public boolean isSharingIndex() { return sharingIndex; } /** * Sets the sharingIndex flag. * @param sharingIndex false means this app should have its own dedicated index */ public void setSharingIndex(boolean sharingIndex) { this.sharingIndex = sharingIndex; } /** * Is this a sharing the database table with other apps. * @return true if it does */ public boolean isSharingTable() { return sharingTable; } /** * Sets the sharingTable flag. * @param sharingTable false means this app should have its own dedicated table */ public void setSharingTable(boolean sharingTable) { this.sharingTable = sharingTable; } /** * @return returns true only if app has its own dedicated index and DB table */ public boolean isShared() { return sharingIndex || sharingTable; } /** * Return true if the app is the root app (the first one created). * @return true if root */ @JsonIgnore public boolean isRootApp() { return StringUtils.equals(App.id(Config.APP_NAME_NS), getId()); } /** * Return true if the app is the root app (the first one created). * @param appid an app identifier * @return true if root */ public static boolean isRoot(String appid) { return StringUtils.equals(App.id(Config.APP_NAME_NS), id(appid)); } /** * Returns all validation constraints for a list of types. * @param types a list of valid Para data types * @return a map of validation constraints for given types */ public Map>>> getAllValidationConstraints(String... types) { Map>>> allConstr = new HashMap>>>(); if (types == null || types.length == 0) { types = ParaObjectUtils.getAllTypes(this).values().toArray(new String[0]); } try { for (String aType : types) { Map>> vc = new HashMap>>(); // add all core constraints first if (ValidationUtils.getCoreValidationConstraints().containsKey(aType)) { vc.putAll(ValidationUtils.getCoreValidationConstraints().get(aType)); } // also add the ones that are defined locally for this app Map>> appConstraints = getValidationConstraints().get(aType); if (appConstraints != null && !appConstraints.isEmpty()) { vc.putAll(appConstraints); } if (!vc.isEmpty()) { allConstr.put(aType, vc); } } } catch (Exception ex) { logger.error(null, ex); } return allConstr; } /** * Adds a new constraint to the list of constraints for a given field and type. * @param type the type * @param field the field * @param c the constraint * @return true if successful */ public boolean addValidationConstraint(String type, String field, Constraint c) { if (!StringUtils.isBlank(type) && !StringUtils.isBlank(field) && c != null && !c.getPayload().isEmpty() && Constraint.isValidConstraintName(c.getName())) { Map>> fieldMap = getValidationConstraints().get(type); Map> consMap; if (fieldMap != null) { consMap = fieldMap.get(field); if (consMap == null) { consMap = new HashMap>(); } } else { fieldMap = new HashMap>>(); consMap = new HashMap>(); } consMap.put(c.getName(), c.getPayload()); fieldMap.put(field, consMap); getValidationConstraints().put(type, fieldMap); return true; } return false; } /** * Removes a constraint from the map. * @param type the type * @param field the field * @param constraintName the constraint name * @return true if successful */ public boolean removeValidationConstraint(String type, String field, String constraintName) { if (!StringUtils.isBlank(type) && !StringUtils.isBlank(field) && constraintName != null) { Map>> fieldsMap = getValidationConstraints().get(type); if (fieldsMap != null && fieldsMap.containsKey(field)) { if (fieldsMap.get(field).containsKey(constraintName)) { fieldsMap.get(field).remove(constraintName); } if (fieldsMap.get(field).isEmpty()) { getValidationConstraints().get(type).remove(field); } if (getValidationConstraints().get(type).isEmpty()) { getValidationConstraints().remove(type); } return true; } } return false; } /** * Returns all resource permission for a list of subjects ids. * @param subjectids subject ids (user ids) * @return a map of all resource permissions per subject */ public Map>> getAllResourcePermissions(String... subjectids) { Map>> allPermits = new HashMap>>(); if (subjectids == null || subjectids.length == 0) { return getResourcePermissions(); } try { for (String subjectid : subjectids) { if (subjectid != null) { if (getResourcePermissions().containsKey(subjectid)) { allPermits.put(subjectid, getResourcePermissions().get(subjectid)); } else { allPermits.put(subjectid, new HashMap>(0)); } if (getResourcePermissions().containsKey(ALLOW_ALL)) { allPermits.put(ALLOW_ALL, getResourcePermissions().get(ALLOW_ALL)); } } } } catch (Exception ex) { logger.error(null, ex); } return allPermits; } /** * Grants a new permission for a given subject and resource. * @param subjectid the subject to give permissions to * @param resourcePath the resource name/type * @param permission the set or HTTP methods allowed * @return true if successful */ public boolean grantResourcePermission(String subjectid, String resourcePath, EnumSet permission) { return grantResourcePermission(subjectid, resourcePath, permission, false); } /** * Grants a new permission for a given subject and resource. * @param subjectid the subject to give permissions to * @param resourcePath the resource name/type * @param permission the set or HTTP methods allowed * @param allowGuestAccess if true - all unauthenticated requests will go through, 'false' by default. * @return true if successful */ public boolean grantResourcePermission(String subjectid, String resourcePath, EnumSet permission, boolean allowGuestAccess) { // urlDecode resource path & strip slashes at both ends resourcePath = Utils.urlDecode(resourcePath); resourcePath = StringUtils.removeEnd(resourcePath, "/"); resourcePath = StringUtils.removeStart(resourcePath, "/"); resourcePath = StringUtils.remove(resourcePath, "."); // ElasticSearch 2.0+ restriction if (!StringUtils.isBlank(subjectid) && !StringUtils.isBlank(resourcePath) && permission != null && !permission.isEmpty()) { allowGuestAccess = permission.remove(GUEST) || allowGuestAccess; EnumSet methods = EnumSet.copyOf(permission); if (!getResourcePermissions().containsKey(subjectid)) { Map> perm = new HashMap>(); perm.put(resourcePath, new ArrayList(permission.size())); getResourcePermissions().put(subjectid, perm); } if (isAllowAllPermission(permission)) { methods = EnumSet.copyOf(READ_AND_WRITE); } else { if (permission.contains(WRITE_ONLY)) { methods = EnumSet.copyOf(READ_AND_WRITE); } else if (permission.contains(READ_ONLY)) { methods = EnumSet.copyOf(READ_AND_WRITE); } } if (allowGuestAccess && ALLOW_ALL.equals(subjectid)) { methods.add(GUEST); } List perm = new ArrayList(methods.size()); for (AllowedMethods allowedMethod : methods) { perm.add(allowedMethod.toString()); } getResourcePermissions().get(subjectid).put(resourcePath, perm); return true; } return false; } private boolean isAllowAllPermission(EnumSet permission) { return permission != null && (permission.containsAll(ALL) || permission.contains(READ_WRITE) || // * || rw = * (permission.contains(READ_ONLY) && permission.contains(WRITE_ONLY)) || // r + w = * (permission.contains(GET) && permission.contains(WRITE_ONLY))); // r + w = * } /** * Revokes a permission for given subject. * @param subjectid subject id * @param resourcePath resource path or object type * @return true if successful */ public boolean revokeResourcePermission(String subjectid, String resourcePath) { if (!StringUtils.isBlank(subjectid) && getResourcePermissions().containsKey(subjectid) && !StringUtils.isBlank(resourcePath)) { // urlDecode resource path resourcePath = Utils.urlDecode(resourcePath); getResourcePermissions().get(subjectid).remove(resourcePath); if (getResourcePermissions().get(subjectid).isEmpty()) { getResourcePermissions().remove(subjectid); } return true; } return false; } /** * Revokes all permissions for a subject id. * @param subjectid subject id * @return true if successful */ public boolean revokeAllResourcePermissions(String subjectid) { if (!StringUtils.isBlank(subjectid) && getResourcePermissions().containsKey(subjectid)) { getResourcePermissions().remove(subjectid); return true; } return false; } /** * Checks if a subject is allowed to call method X on resource Y. * @param subjectid subject id * @param resourcePath resource path or object type * @param httpMethod HTTP method name * @return true if allowed */ public boolean isAllowedTo(String subjectid, String resourcePath, String httpMethod) { boolean allow = false; if (subjectid != null && !StringUtils.isBlank(resourcePath) && !StringUtils.isBlank(httpMethod)) { // urlDecode resource path resourcePath = Utils.urlDecode(resourcePath); if (getResourcePermissions().isEmpty()) { // Default policy is "deny all". Returning true here would make it "allow all". return false; } if (getResourcePermissions().containsKey(subjectid) && getResourcePermissions().get(subjectid).containsKey(resourcePath)) { // subject-specific permissions have precedence over wildcard permissions // i.e. only the permissions for that subjectid are checked, other permissions are ignored allow = isAllowed(subjectid, resourcePath, httpMethod); } else { allow = isAllowed(subjectid, resourcePath, httpMethod) || isAllowed(subjectid, ALLOW_ALL, httpMethod) || isAllowed(ALLOW_ALL, resourcePath, httpMethod) || isAllowed(ALLOW_ALL, ALLOW_ALL, httpMethod); } } if (allow) { if (isRootApp() && !Config.getConfigBoolean("clients_can_access_root_app", false)) { return false; } if (StringUtils.isBlank(subjectid)) { // guest access check return isAllowed(ALLOW_ALL, resourcePath, GUEST.toString()); } return true; } return false; } protected final boolean isAllowed(String subjectid, String resourcePath, String httpMethod) { boolean allowed = false; if (subjectid != null && httpMethod != null && getResourcePermissions().containsKey(subjectid)) { httpMethod = httpMethod.toUpperCase(); String wildcard = ALLOW_ALL; if (fromString(httpMethod) == GUEST) { // special case where we have wildcard permissions * but public access is not allowed wildcard = httpMethod; } if (StringUtils.contains(resourcePath, '/')) { // we assume that a full resource path is given like: 'users/something/123' // so we check to see if 'users/something' is in the list of resources // if there is only 'users' this will match, also 'users/someth' matches String fragment = resourcePath.substring(0, resourcePath.lastIndexOf('/')); for (String resource : getResourcePermissions().get(subjectid).keySet()) { if (StringUtils.startsWith(fragment, resource) && ( getResourcePermissions().get(subjectid).get(resource).contains(httpMethod) || getResourcePermissions().get(subjectid).get(resource).contains(wildcard))) { allowed = true; break; } } } if (!allowed && getResourcePermissions().get(subjectid).containsKey(resourcePath)) { // check exact resource path as it is allowed = (getResourcePermissions().get(subjectid).get(resourcePath).contains(httpMethod) || getResourcePermissions().get(subjectid).get(resourcePath).contains(wildcard)); } } return allowed; } /** * Check if a subject is explicitly denied access to a resource. * @param subjectid subject id * @param resourcePath resource path or object type * @param httpMethod HTTP method name * @return true if access is explicitly denied */ public boolean isDeniedExplicitly(String subjectid, String resourcePath, String httpMethod) { if (StringUtils.isBlank(subjectid) || StringUtils.isBlank(resourcePath) || StringUtils.isBlank(httpMethod) || getResourcePermissions().isEmpty()) { return false; } // urlDecode resource path resourcePath = Utils.urlDecode(resourcePath); String sid, path; if (getResourcePermissions().containsKey(subjectid)) { sid = subjectid; } else if (getResourcePermissions().containsKey(ALLOW_ALL)) { sid = ALLOW_ALL; } else { return false; } if (getResourcePermissions().get(sid).containsKey(resourcePath)) { path = resourcePath; } else if (getResourcePermissions().get(sid).containsKey(ALLOW_ALL)) { path = ALLOW_ALL; } else { return false; } return !isAllowed(sid, path, httpMethod); } /** * Adds a user-defined data type to the types map. * @param pluralDatatype the plural form of the type * @param datatype a datatype, must not be null or empty */ public void addDatatype(String pluralDatatype, String datatype) { pluralDatatype = Utils.noSpaces(Utils.stripAndTrim(pluralDatatype, " "), "-"); datatype = Utils.noSpaces(Utils.stripAndTrim(datatype, " "), "-"); if (StringUtils.isBlank(pluralDatatype) || StringUtils.isBlank(datatype)) { return; } if (getDatatypes().size() >= Config.MAX_DATATYPES_PER_APP) { LoggerFactory.getLogger(App.class).warn("Maximum number of types per app reached - {}.", Config.MAX_DATATYPES_PER_APP); return; } if (!getDatatypes().containsKey(pluralDatatype) && !getDatatypes().containsValue(datatype) && !ParaObjectUtils.getCoreTypes().containsKey(pluralDatatype)) { getDatatypes().put(pluralDatatype, datatype); } } /** * Adds unknown types to this app's list of data types. Called on create(). * @param objects a list of new objects */ public void addDatatypes(ParaObject... objects) { // register a new data type if (objects != null && objects.length > 0) { for (ParaObject obj : objects) { if (obj != null && obj.getType() != null) { addDatatype(obj.getPlural(), obj.getType()); } } } } /** * Removes a datatype from the types map. * @param pluralDatatype a datatype, must not be null or empty */ public void removeDatatype(String pluralDatatype) { if (!StringUtils.isBlank(pluralDatatype)) { getDatatypes().remove(pluralDatatype); } } /** * Resets the secret key by generating a new one. */ public void resetSecret() { secret = Utils.generateSecurityToken(40); } /** * Returns the map containing the app's access key and secret key. * @return a map of API keys (never null) */ @JsonIgnore public Map getCredentials() { if (getId() == null) { return Collections.emptyMap(); } else { return new HashMap() { private static final long serialVersionUID = 1L; { put("accessKey", getId()); put("secretKey", getSecret()); } }; } } @Override public String create() { if (getId() != null && this.exists()) { return null; } if (!Config.APP_NAME_NS.equals(getAppid())) { // third level apps not allowed return null; } if (StringUtils.isBlank(secret)) { resetSecret(); } return CoreUtils.getInstance().getDao().create(getAppid(), this); } @Override public void delete() { // root app cannot be deleted if (!isRootApp()) { CoreUtils.getInstance().getDao().delete(getAppid(), this); logger.info("App '{}' deleted.", getId()); } } //////////////////////////////////////////////////////// @Override public final String getId() { return id; } @Override public final String getType() { type = (type == null) ? Utils.type(this.getClass()) : type; return type; } @Override public final void setType(String type) { this.type = type; } @Override public String getAppid() { appid = (appid == null) ? Config.APP_NAME_NS : appid; return appid; } @Override public void setAppid(String appid) { this.appid = appid; } @Override public String getObjectURI() { return CoreUtils.getInstance().getObjectURI(this); } @Override public List getTags() { return tags; } @Override public void setTags(List tags) { this.tags = tags; } @Override public Boolean getStored() { if (stored == null) { stored = true; } return stored; } @Override public void setStored(Boolean stored) { this.stored = stored; } @Override public Boolean getIndexed() { if (indexed == null) { indexed = true; } return indexed; } @Override public void setIndexed(Boolean indexed) { this.indexed = indexed; } @Override public Boolean getCached() { if (cached == null) { cached = true; } return cached; } @Override public void setCached(Boolean cached) { this.cached = cached; } @Override public Long getTimestamp() { return (timestamp != null && timestamp != 0) ? timestamp : null; } @Override public void setTimestamp(Long timestamp) { this.timestamp = timestamp; } @Override public String getCreatorid() { return creatorid; } @Override public void setCreatorid(String creatorid) { this.creatorid = creatorid; } @Override public final String getName() { return CoreUtils.getInstance().getName(name, id); } @Override public final void setName(String name) { this.name = (name == null || !name.isEmpty()) ? name : this.name; } @Override public String getPlural() { return Utils.singularToPlural(getType()); } @Override public String getParentid() { return parentid; } @Override public void setParentid(String parentid) { this.parentid = parentid; } @Override public Long getUpdated() { return (updated != null && updated != 0) ? updated : null; } @Override public void setUpdated(Long updated) { this.updated = updated; } @Override public void update() { CoreUtils.getInstance().getDao().update(getAppid(), this); } @Override public boolean exists() { return CoreUtils.getInstance().getDao().read(getAppid(), getId()) != null; } @Override public boolean voteUp(String userid) { return CoreUtils.getInstance().vote(this, userid, VoteValue.UP); } @Override public boolean voteDown(String userid) { return CoreUtils.getInstance().vote(this, userid, VoteValue.DOWN); } @Override public Integer getVotes() { return (votes == null) ? 0 : votes; } @Override public void setVotes(Integer votes) { this.votes = votes; } @Override public Long countLinks(String type2) { return CoreUtils.getInstance().countLinks(this, type2); } @Override public List getLinks(String type2, Pager... pager) { return CoreUtils.getInstance().getLinks(this, type2, pager); } @Override public

List

getLinkedObjects(String type, Pager... pager) { return CoreUtils.getInstance().getLinkedObjects(this, type, pager); } @Override public

List

findLinkedObjects(String type, String field, String query, Pager... pager) { return CoreUtils.getInstance().findLinkedObjects(this, type, field, query, pager); } @Override public boolean isLinked(String type2, String id2) { return CoreUtils.getInstance().isLinked(this, type2, id2); } @Override public boolean isLinked(ParaObject toObj) { return CoreUtils.getInstance().isLinked(this, toObj); } @Override public String link(String id2) { return CoreUtils.getInstance().link(this, id2); } @Override public void unlink(String type, String id2) { CoreUtils.getInstance().unlink(this, type, id2); } @Override public void unlinkAll() { CoreUtils.getInstance().unlinkAll(this); } @Override public Long countChildren(String type) { return CoreUtils.getInstance().countChildren(this, type); } @Override public

List

getChildren(String type, Pager... pager) { return CoreUtils.getInstance().getChildren(this, type, pager); } @Override public

List

getChildren(String type, String field, String term, Pager... pager) { return CoreUtils.getInstance().getChildren(this, type, field, term, pager); } @Override public

List

findChildren(String type, String query, Pager... pager) { return CoreUtils.getInstance().findChildren(this, type, query, pager); } @Override public void deleteChildren(String type) { CoreUtils.getInstance().deleteChildren(this, type); } @Override public int hashCode() { int hash = 7; hash = 67 * hash + Objects.hashCode(this.id) + Objects.hashCode(this.name); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ParaObject other = (ParaObject) obj; return Objects.equals(this.id, other.getId()); } @Override public String toString() { return ParaObjectUtils.toJSON(this); } /** * Represents HTTP methods allowed to be executed on a specific resource/type. * For example; the 'books' type can have a permission '{ "*" : ["GET"] }' which means * "give read-only permissions to everyone". It is backed by a map of resource names * (object types) to a set of allowed HTTP methods. */ public enum AllowedMethods { /** * Allow unauthenticated requests (guest access). */ GUEST, /** * Deny all requests (no access). */ EMPTY, /** * Allows all HTTP methods (full access). */ READ_WRITE, /** * Allows GET method only. */ GET, /** * Allows POST method only. */ POST, /** * Allows PUT method only. */ PUT, /** * ALlows PATCH method only. */ PATCH, /** * Allows DELETE method only. */ DELETE, /** * Allows read methods: GET, same as {@link #GET}. */ READ_ONLY, /** * Allows write methods: POST, PUT, PATCH and DELETE. */ WRITE_ONLY; /** * All methods allowed. */ public static final EnumSet ALL = EnumSet.of(GET, POST, PUT, PATCH, DELETE); /** * All methods allowed (*). */ public static final EnumSet READ_AND_WRITE = EnumSet.of(READ_WRITE); /** * Only GET is allowed. */ public static final EnumSet READ = EnumSet.of(GET); /** * All methods allowed, except GET. */ public static final EnumSet WRITE = EnumSet.of(POST, PUT, PATCH, DELETE); /** * All methods allowed, except DELETE. */ public static final EnumSet ALL_EXCEPT_DELETE = EnumSet.of(GET, POST, PUT, PATCH); /** * No methods allowed. */ public static final EnumSet NONE = EnumSet.of(EMPTY); /** * Constructs the enum from a string value. * @param value a method name, or ?,w * @return an enum instance */ @JsonCreator public static AllowedMethods fromString(String value) { if (ALLOW_ALL.equals(value)) { return READ_WRITE; } else if ("w".equals(value)) { return WRITE_ONLY; } else if ("?".equals(value)) { return GUEST; } else { try { return valueOf(value.toUpperCase()); } catch (Exception e) { return EMPTY; } } } @Override @JsonValue public String toString() { switch (this) { case READ_WRITE: return ALLOW_ALL; case READ_ONLY: return GET.name(); case GUEST: return "?"; case EMPTY: return "-"; case WRITE_ONLY: return "w"; default: return this.name(); } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy