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

com.bluenimble.platform.api.validation.impls.DefaultApiServiceValidator Maven / Gradle / Ivy

There is a newer version: 2.50.0
Show newest version
/*
 * 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 com.bluenimble.platform.api.validation.impls;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import com.bluenimble.platform.Json;
import com.bluenimble.platform.Lang;
import com.bluenimble.platform.api.Api;
import com.bluenimble.platform.api.ApiRequest;
import com.bluenimble.platform.api.ApiRequest.Scope;
import com.bluenimble.platform.api.ApiResponse;
import com.bluenimble.platform.api.ApiService;
import com.bluenimble.platform.api.security.ApiConsumer;
import com.bluenimble.platform.api.validation.ApiServiceValidator;
import com.bluenimble.platform.api.validation.ApiServiceValidatorException;
import com.bluenimble.platform.api.validation.FieldType;
import com.bluenimble.platform.api.validation.TypeValidator;
import com.bluenimble.platform.api.validation.ValueTransformer;
import com.bluenimble.platform.api.validation.impls.transformers.AppendValueTransformer;
import com.bluenimble.platform.api.validation.impls.transformers.LowerCaseValueTransformer;
import com.bluenimble.platform.api.validation.impls.transformers.PrependValueTransformer;
import com.bluenimble.platform.api.validation.impls.transformers.ReplaceValueTransformer;
import com.bluenimble.platform.api.validation.impls.transformers.TruncateValueTransformer;
import com.bluenimble.platform.api.validation.impls.transformers.UpperCaseValueTransformer;
import com.bluenimble.platform.api.validation.impls.types.AlphaNumericValidator;
import com.bluenimble.platform.api.validation.impls.types.ArrayValidator;
import com.bluenimble.platform.api.validation.impls.types.Base64Validator;
import com.bluenimble.platform.api.validation.impls.types.BinaryValidator;
import com.bluenimble.platform.api.validation.impls.types.BooleanValidator;
import com.bluenimble.platform.api.validation.impls.types.ContainsValidator;
import com.bluenimble.platform.api.validation.impls.types.DateTimeValidator;
import com.bluenimble.platform.api.validation.impls.types.DateValidator;
import com.bluenimble.platform.api.validation.impls.types.DecimalValidator;
import com.bluenimble.platform.api.validation.impls.types.EmailValidator;
import com.bluenimble.platform.api.validation.impls.types.EndsWithValidator;
import com.bluenimble.platform.api.validation.impls.types.FloatValidator;
import com.bluenimble.platform.api.validation.impls.types.IntegerValidator;
import com.bluenimble.platform.api.validation.impls.types.LongValidator;
import com.bluenimble.platform.api.validation.impls.types.MapValidator;
import com.bluenimble.platform.api.validation.impls.types.PhoneValidator;
import com.bluenimble.platform.api.validation.impls.types.RegexValidator;
import com.bluenimble.platform.api.validation.impls.types.StartsWithValidator;
import com.bluenimble.platform.api.validation.impls.types.StreamValidator;
import com.bluenimble.platform.api.validation.impls.types.StringValidator;
import com.bluenimble.platform.api.validation.impls.types.UUIDValidator;
import com.bluenimble.platform.api.validation.impls.types.UrlValidator;
import com.bluenimble.platform.json.JsonArray;
import com.bluenimble.platform.json.JsonObject;

public class DefaultApiServiceValidator implements ApiServiceValidator {

	private static final long serialVersionUID = 7521000052639259961L;
		
	private static final char ConsumerScope = 'c';

	private static final Map Scopes 	= new HashMap ();
	static {
		// scopes
		Scopes.put ("h", Scope.Header);
		Scopes.put ("p", Scope.Parameter);
		Scopes.put ("s", Scope.Stream);
	}
	
	private static final String DefaultScope = "p";
	
	private Map validators 		= new HashMap ();
	
	private Map transformers 	= new HashMap ();
	
	public DefaultApiServiceValidator () {
		// transformers
		addValueTransformer (ValueTransformer.Default.LowerCase, 	new LowerCaseValueTransformer ());
		addValueTransformer (ValueTransformer.Default.UpperCase, 	new UpperCaseValueTransformer ());
		addValueTransformer (ValueTransformer.Default.Append, 		new AppendValueTransformer ());
		addValueTransformer (ValueTransformer.Default.Prepend, 		new PrependValueTransformer ());
		addValueTransformer (ValueTransformer.Default.Truncate, 	new TruncateValueTransformer ());
		addValueTransformer (ValueTransformer.Default.Replace, 		new ReplaceValueTransformer ());

		// validators
		addTypeValidator (FieldType.String.toLowerCase (), 			new StringValidator ());
		addTypeValidator (FieldType.AlphaNumeric.toLowerCase (), 	new AlphaNumericValidator ());
		
		addTypeValidator (FieldType.Boolean.toLowerCase (), 		new BooleanValidator ());
		
		addTypeValidator (FieldType.Integer.toLowerCase (), 		new IntegerValidator ());
		addTypeValidator (FieldType.Long.toLowerCase (), 			new LongValidator ());
		addTypeValidator (FieldType.Decimal.toLowerCase (), 		new DecimalValidator ());
		addTypeValidator (FieldType.Float.toLowerCase (), 			new FloatValidator ());
		
		addTypeValidator (FieldType.Date.toLowerCase (), 			new DateValidator ());
		addTypeValidator (FieldType.DateTime.toLowerCase (), 		new DateTimeValidator ());
		
		addTypeValidator (FieldType.Object.toLowerCase (), 			new MapValidator ());
		addTypeValidator (FieldType.Array.toLowerCase (), 			new ArrayValidator ());
		
		addTypeValidator (FieldType.Stream.toLowerCase (), 			new StreamValidator ());
		addTypeValidator (FieldType.Base64.toLowerCase (), 			new Base64Validator ());
		addTypeValidator (FieldType.Binary.toLowerCase (), 			new BinaryValidator ());
		
		addTypeValidator (FieldType.UUID.toLowerCase (), 			new UUIDValidator ());
		
		// vtypes
		addTypeValidator (FieldType.Facets.StartsWith.toLowerCase (),new StartsWithValidator ());
		addTypeValidator (FieldType.Facets.EndsWith.toLowerCase (), new EndsWithValidator ());
		addTypeValidator (FieldType.Facets.Contains.toLowerCase (), new ContainsValidator ());

		addTypeValidator (FieldType.Facets.Email.toLowerCase (), 	new EmailValidator ());
		addTypeValidator (FieldType.Facets.Url.toLowerCase (), 		new UrlValidator ());
		addTypeValidator (FieldType.Facets.Phone.toLowerCase (), 	new PhoneValidator ());
		
		addTypeValidator (FieldType.Facets.Regex.toLowerCase (), 	new RegexValidator ());

	}
	
	@Override
	public void validate (Api context, JsonObject spec, ApiConsumer consumer, ApiRequest request) 
		throws ApiServiceValidatorException {
		validate (context, spec, consumer, request, null);
	}
	
	public void validate (Api api, JsonObject spec, ApiConsumer consumer, ApiRequest request, Map data) 
		throws ApiServiceValidatorException {
		
		String refServiceId = null;
		String refField = null;
		
		String refSpec = Json.getString (spec, Spec.RefSpec);
		if (!Lang.isNullOrEmpty (refSpec)) {
			refSpec = refSpec.trim ();
			int indexOfSharp = refSpec.indexOf (Lang.SHARP);
			if (indexOfSharp > 0) {
				refServiceId 	= refSpec.substring (0, indexOfSharp).trim ();
				refField 		= refSpec.substring (indexOfSharp + 1).trim ();
			}
		}
		
		if (!Lang.isNullOrEmpty (refServiceId)) {
			ApiService refService = api.getServicesManager ().getById (refServiceId);
			if (refService != null && !Json.isNullOrEmpty (refService.getSpecification ())) {
				JsonObject oRefSpec = refService.getSpecification ();
				if (!Lang.isNullOrEmpty (refField)) {
					refField = Spec.Fields + Lang.DOT + refField;
					Object fieldSpec = Json.find (oRefSpec, Lang.split (refField, Lang.DOT));
					if (fieldSpec != null && (fieldSpec instanceof JsonObject)) {
						oRefSpec = (JsonObject)fieldSpec;
					}
				}
				oRefSpec.duplicate ().merge (spec);
				spec = oRefSpec;
			}
		}

		if (Json.isNullOrEmpty (spec)) {
			return;
		}
		
		JsonObject oFields = Json.getObject (spec, Spec.Fields);
		JsonObject altSpec = 
			Json.getObject (
				Json.getObject (spec, Spec.Selectors),
				(String)request.get (ApiRequest.SelectSpec)
			);
		
		if (Json.isNullOrEmpty (oFields)) {
			// any alternative spec
			if (!Json.isNullOrEmpty (altSpec)) {
				validate (api, altSpec, consumer, request, data);
			}
			return;
		}
		
		JsonObject feedback = null;
		
		Iterator fields = oFields.keys ();
		while (fields.hasNext ()) {
			String name = fields.next ();
			
			Object oSpec = oFields.get (name);
			if (! (oSpec instanceof JsonObject) ) {
				if (feedback == null) {
					feedback = new JsonObject ();
				}
				feedback.set (name, ValidationUtils.feedback (
					null, spec, Spec.Type, 
					"field definition should be a valid object"
				));
				continue;
			}
			
			JsonObject fSpec = (JsonObject)oSpec;
			
			String type = Json.getString (fSpec, Spec.Type, FieldType.String);
			
			if (type.equalsIgnoreCase (FieldType.Raw)) {
				continue;
			}
			
			TypeValidator validator = getTypeValidator (type);
			if (validator == null) {
				validator = getTypeValidator (FieldType.Object);
			}
			
			String label = getLabel (name, fSpec.getString (Spec.Title));
			
			Object value = valueOf (name, fSpec, request, consumer, data);
			
			JsonArray transforms = Json.getArray (fSpec, Spec.Transforms);
			if (!Json.isNullOrEmpty (transforms)) {
				for (int i = 0; i < transforms.count (); i++) {
					JsonObject oTransform = (JsonObject)transforms.get (i);
					String transformName = Json.getString (oTransform, Spec.Name);
					ValueTransformer t = getValueTransformer (transformName);
					if (t == null) {
						continue;
					}
					value = t.transform (this, Json.getObject (oTransform, Spec.Spec), value);
				}
			}
			
			Object message = validator.validate (
				api,
				consumer, 
				request, 	
				this,
				name,
				label,
				fSpec, 
				value
			);
						
			if (message != null) {
				if (message instanceof JsonObject) {
					// it's an error
					if (feedback == null) {
						feedback = new JsonObject ();
					}
					feedback.set (name, message);
				} else {
					// it a value cast. set new value...
					if (data != null) {
						data.put (name, message);
					} else {
						request.set (name, message, Scope.Parameter);
					}
				}
			}
		}
		
		if (feedback != null && !feedback.isEmpty ()) {
			ApiServiceValidatorException vex = new ApiServiceValidatorException (feedback);
			ApiResponse.Status status = (ApiResponse.Status)request.get (ApiRequest.ResponseStatus);
			if (status != null) {
				vex.status (status);
			}
			throw vex;
		}
		
		// any alternative spec
		if (!Json.isNullOrEmpty (altSpec)) {
			validate (api, altSpec, consumer, request, data);
		}
		
	}

	private String getLabel (String name, String title) {
		if (Lang.isNullOrEmpty (title)) {
			return name;
		}
		return title;
	}
	
	@Override
	public void addTypeValidator (String name, TypeValidator validator) {
		validators.put (name.toLowerCase (), validator);
	}

	@Override
	public TypeValidator getTypeValidator (String name) {
		return validators.get (name.toLowerCase ());
	}

	@Override
	public String getMessage (Api api, String lang, String key, Object... args) {
		return api.message (lang, key, args);
	}
	
	public Object valueOf (String name, JsonObject fieldSpec, ApiRequest request, ApiConsumer consumer, Map data) {
		
		Object defaultValue = fieldSpec.get (Spec.Value);
		
		if (data != null) {
			Object dValue = data.get (name);
			if (dValue == null) {
				dValue = defaultValue;
			}
			return dValue;
		}
		
		Object value = null;
		
		String s = fieldSpec.getString (Spec.Scope);
		if (Lang.isNullOrEmpty (s)) {
			s = DefaultScope;
		}
		
		Scope scope = null;
		s = s.trim ();
		for (int i = 0; i < s.length (); i++) {
			char sc = s.charAt (i);
			if (ConsumerScope == sc) {
				if (defaultValue != null) {
					value = getFromConsumer (consumer, defaultValue.toString ());
				}
				continue;
			}
			scope = Scopes.get (String.valueOf (sc));
			if (scope == null) {
				continue;
			}
			value = request.get (name, scope);
			if (value != null) {
				break;
			}
		}
		
		if (value == null) {
			value = defaultValue;
		}
		
		if (value != null) {
			request.set (name, value);
		}
		
		return value;
		
	}

	@Override
	public boolean isCustomType (String type) {
		if (type == null) {
			return false;
		}
		return !validators.containsKey (type.toLowerCase ());
	}
	
	private Object getFromConsumer (ApiConsumer consumer, String property) {
		if (Lang.isNullOrEmpty (property)) {
			return null;
		}
		
		String [] accessors = Lang.split (property, Lang.DOT);
		
		Object value = consumer.get (accessors [0]);

		if (accessors.length == 1) {
			return value;
		}
		
		if (!(value instanceof JsonObject)) {
			return null;
		}
		
		return Json.find ((JsonObject)value, Lang.moveLeft (accessors, 1));
	}

	@Override
	public void addValueTransformer (String name, ValueTransformer validator) {
		transformers.put (name.toLowerCase (), validator);
	}

	@Override
	public ValueTransformer getValueTransformer (String name) {
		return transformers.get (name.toLowerCase ());
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy