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

org.rapidoid.render.retriever.GenericValueRetriever Maven / Gradle / Ivy

The newest version!
/*-
 * #%L
 * rapidoid-render
 * %%
 * Copyright (C) 2014 - 2018 Nikolche Mihajlovski and contributors
 * %%
 * 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.
 * #L%
 */

package org.rapidoid.render.retriever;


import org.rapidoid.RapidoidThing;
import org.rapidoid.annotation.Authors;
import org.rapidoid.annotation.Since;
import org.rapidoid.beany.BeanProp;
import org.rapidoid.beany.Beany;
import org.rapidoid.beany.Prop;
import org.rapidoid.render.Getter;
import org.rapidoid.u.U;

import java.util.Collections;
import java.util.List;
import java.util.Map;

@Authors("Nikolche Mihajlovski")
@Since("5.2.0")
public class GenericValueRetriever extends RapidoidThing implements ValueRetriever {

	private final String property;

	private volatile CachedPropRetriever cachedPropRetriever;

	public GenericValueRetriever(String property) {
		this.property = property;
	}

	@Override
	public Object retrieve(List model) {
		if (U.isEmpty(model)) return null;
		return getProp(model);
	}

	private Object getProp(List model) {
		Object target = U.last(model);
		Class cls = target.getClass();

		CachedPropRetriever cachedProp = cachedPropRetriever;
		if (cachedProp != null && cachedProp.canRetrieve(cls)) {
			return cachedProp.retrieve(target);
		}

		if (!(target instanceof Map)) {
			Prop prop = Beany.property(target, property, false);

			if (prop != null && prop instanceof BeanProp) {
				cachedPropRetriever = new CachedPropRetriever(cls, prop);
				return prop.getFast(target);
			}
		}

		return propOf(property, model);
	}

	public static Object self(List model) {
		return model.get(model.size() - 1);
	}

	public static Object propOf(String name, List scope) {
		int p = name.indexOf(".");

		if (p == 0) {
			U.must(name.length() == 1, "Invalid expression!");
			return self(scope);
		}

		if (p > 0) {
			Object first = propOf(name.substring(0, p), scope);
			return propOf(name.substring(p + 1), Collections.singletonList(first));
		}

		for (int i = scope.size() - 1; i >= 0; i--) {
			Object x = scope.get(i);

			if (x != null) {
				Object value = singleModelProp(name, x);
				if (value != null) return value;
			}
		}

		return null;
	}

	public static Object singleModelProp(String name, Object model) {

		if (model instanceof Map) {
			Map map = (Map) model;
			return map.get(name);
		}

		if (model instanceof Getter) {
			Getter getter = (Getter) model;
			return getter.get(name);
		}

		// process as bean
		Prop prop = Beany.property(model, name, false);

		if (prop != null) {
			return prop.get(model);
		}

		return null; // not found
	}

}