<commit_before>/**
 * The contents of this file are subject to the OpenMRS Public License
 * Version 1.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://license.openmrs.org
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * Copyright (C) OpenMRS, LLC.  All Rights Reserved.
 */
package org.openmrs.module.webservices.rest.web.resource.impl;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.proxy.HibernateProxy;
import org.openmrs.OpenmrsObject;
import org.openmrs.api.context.Context;
import org.openmrs.module.ModuleUtil;
import org.openmrs.module.webservices.rest.SimpleObject;
import org.openmrs.module.webservices.rest.util.ReflectionUtil;
import org.openmrs.module.webservices.rest.web.ConversionUtil;
import org.openmrs.module.webservices.rest.web.Hyperlink;
import org.openmrs.module.webservices.rest.web.RequestContext;
import org.openmrs.module.webservices.rest.web.RestConstants;
import org.openmrs.module.webservices.rest.web.annotation.PropertyGetter;
import org.openmrs.module.webservices.rest.web.annotation.PropertySetter;
import org.openmrs.module.webservices.rest.web.annotation.RepHandler;
import org.openmrs.module.webservices.rest.web.annotation.SubClassHandler;
import org.openmrs.module.webservices.rest.web.annotation.SubResource;
import org.openmrs.module.webservices.rest.web.api.RestService;
import org.openmrs.module.webservices.rest.web.representation.CustomRepresentation;
import org.openmrs.module.webservices.rest.web.representation.RefRepresentation;
import org.openmrs.module.webservices.rest.web.representation.Representation;
import org.openmrs.module.webservices.rest.web.resource.api.Converter;
import org.openmrs.module.webservices.rest.web.resource.api.Resource;
import org.openmrs.module.webservices.rest.web.resource.impl.DelegatingResourceDescription.Property;
import org.openmrs.module.webservices.rest.web.response.ConversionException;
import org.openmrs.module.webservices.rest.web.response.ResourceDoesNotSupportOperationException;
import org.openmrs.module.webservices.rest.web.response.ResponseException;

import org.openmrs.util.OpenmrsConstants;
import org.openmrs.util.OpenmrsUtil;

/**
 * A base implementation of a resource or sub-resource that delegates operations to a wrapped
 * object. Implementations generally should extend either {@link DelegatingCrudResource} or
 * {@link DelegatingSubResource} rather than this class directly.
 * 
 * @param <T> the class we're delegating to
 */
public abstract class BaseDelegatingResource<T> implements Converter<T>, Resource, DelegatingResourceHandler<T> {
	
	private final Log log = LogFactory.getLog(getClass());
	
	protected Set<String> propertiesIgnoredWhenUpdating = new HashSet<String>();
	
	/**
	 * Properties that should silently be ignored if you try to get them. Implementations should
	 * generally configure this property with a list of properties that were added to their
	 * underlying domain object after the minimum OpenMRS version required by this module. For
	 * example PatientIdentifierTypeResource will allow "locationBehavior" to be missing, since it
	 * wasn't added to PatientIdentifierType until OpenMRS 1.9. delegate class
	 */
	protected Set<String> allowedMissingProperties = new HashSet<String>();
	
	/**
	 * If this resource represents a class hierarchy (rather than a single class), this will hold
	 * handlers for each subclass
	 */
	protected volatile List<DelegatingSubclassHandler<T, ? extends T>> subclassHandlers;
	
	/**
	 * Default constructor will set propertiesIgnoredWhenUpdating to include "display", "links", and
	 * "resourceVersion"
	 */
	protected BaseDelegatingResource() {
		propertiesIgnoredWhenUpdating.add("display");
		propertiesIgnoredWhenUpdating.add("links");
		propertiesIgnoredWhenUpdating.add(RestConstants.PROPERTY_FOR_RESOURCE_VERSION);
	}
	
	/**
	 * All our resources support letting modules register subclass handlers. If any are registered,
	 * then the resource represents a class hierarchy, e.g. requiring a "type" parameter when
	 * creating a new instance.
	 * 
	 * @return whether there are any subclass handlers registered with this resource
	 */
	public boolean hasTypesDefined() {
		return subclassHandlers != null && subclassHandlers.size() > 0;
	}
	
	/**
	 * This will be automatically called with the first call to {@link #getSubclassHandler(Class)}
	 * or {@link #getSubclassHandler(String)}. It finds all subclass handlers intended for this
	 * resource, and registers them.
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public void init() {
		List<DelegatingSubclassHandler<T, ? extends T>> tmpSubclassHandlers = new ArrayList<DelegatingSubclassHandler<T, ? extends T>>();
		
		List<DelegatingSubclassHandler> handlers = Context.getRegisteredComponents(DelegatingSubclassHandler.class);
		for (DelegatingSubclassHandler handler : handlers) {
			
			Class<? extends DelegatingSubclassHandler> handlerClass = handler.getClass();
			Class forDelegateClass = ReflectionUtil.getParameterizedTypeFromInterface(handlerClass,
			    DelegatingSubclassHandler.class, 0);
			Resource resourceForHandler = Context.getService(RestService.class)
			        .getResourceBySupportedClass(forDelegateClass);
			if (getClass().equals(resourceForHandler.getClass())) {
				SubClassHandler annotation = handlerClass.getAnnotation(SubClassHandler.class);
				if (annotation != null) {
					String[] supportedOpenmrsVersions = annotation.supportedOpenmrsVersions();
					for (String version : supportedOpenmrsVersions) {
						if (versionMatches(version)) {
							tmpSubclassHandlers.add(handler);
							break;
						}
					}
				} else {
					log.warn("SubclassHandler "
					        + handlerClass.getName()
					        + " does not have a @SubClassHandler annotation. This can cause conflicts in resolving handlers for your subclass.");
				}
			}
		}
		
		subclassHandlers = tmpSubclassHandlers;
	}
	
	private boolean versionMatches(String supportedVersion) {
		try {
			ModuleUtil.checkRequiredVersion(OpenmrsConstants.OPENMRS_VERSION_SHORT, supportedVersion);
		}
		catch (Exception e) {
			return false;<commit_msg>Explicit error message in an easy-to-do-wrong case.<commit_after>/**
 * The contents of this file are subject to the OpenMRS Public License
 * Version 1.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://license.openmrs.org
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * Copyright (C) OpenMRS, LLC.  All Rights Reserved.
 */
package org.openmrs.module.webservices.rest.web.resource.impl;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.proxy.HibernateProxy;
import org.openmrs.OpenmrsObject;
import org.openmrs.api.context.Context;
import org.openmrs.module.ModuleUtil;
import org.openmrs.module.webservices.rest.SimpleObject;
import org.openmrs.module.webservices.rest.util.ReflectionUtil;
import org.openmrs.module.webservices.rest.web.ConversionUtil;
import org.openmrs.module.webservices.rest.web.Hyperlink;
import org.openmrs.module.webservices.rest.web.RequestContext;
import org.openmrs.module.webservices.rest.web.RestConstants;
import org.openmrs.module.webservices.rest.web.annotation.PropertyGetter;
import org.openmrs.module.webservices.rest.web.annotation.PropertySetter;
import org.openmrs.module.webservices.rest.web.annotation.RepHandler;
import org.openmrs.module.webservices.rest.web.annotation.SubClassHandler;
import org.openmrs.module.webservices.rest.web.annotation.SubResource;
import org.openmrs.module.webservices.rest.web.api.RestService;
import org.openmrs.module.webservices.rest.web.representation.CustomRepresentation;
import org.openmrs.module.webservices.rest.web.representation.RefRepresentation;
import org.openmrs.module.webservices.rest.web.representation.Representation;
import org.openmrs.module.webservices.rest.web.resource.api.Converter;
import org.openmrs.module.webservices.rest.web.resource.api.Resource;
import org.openmrs.module.webservices.rest.web.resource.impl.DelegatingResourceDescription.Property;
import org.openmrs.module.webservices.rest.web.response.ConversionException;
import org.openmrs.module.webservices.rest.web.response.ResourceDoesNotSupportOperationException;
import org.openmrs.module.webservices.rest.web.response.ResponseException;

import org.openmrs.util.OpenmrsConstants;
import org.openmrs.util.OpenmrsUtil;

/**
 * A base implementation of a resource or sub-resource that delegates operations to a wrapped
 * object. Implementations generally should extend either {@link DelegatingCrudResource} or
 * {@link DelegatingSubResource} rather than this class directly.
 * 
 * @param <T> the class we're delegating to
 */
public abstract class BaseDelegatingResource<T> implements Converter<T>, Resource, DelegatingResourceHandler<T> {
	
	private final Log log = LogFactory.getLog(getClass());
	
	protected Set<String> propertiesIgnoredWhenUpdating = new HashSet<String>();
	
	/**
	 * Properties that should silently be ignored if you try to get them. Implementations should
	 * generally configure this property with a list of properties that were added to their
	 * underlying domain object after the minimum OpenMRS version required by this module. For
	 * example PatientIdentifierTypeResource will allow "locationBehavior" to be missing, since it
	 * wasn't added to PatientIdentifierType until OpenMRS 1.9. delegate class
	 */
	protected Set<String> allowedMissingProperties = new HashSet<String>();
	
	/**
	 * If this resource represents a class hierarchy (rather than a single class), this will hold
	 * handlers for each subclass
	 */
	protected volatile List<DelegatingSubclassHandler<T, ? extends T>> subclassHandlers;
	
	/**
	 * Default constructor will set propertiesIgnoredWhenUpdating to include "display", "links", and
	 * "resourceVersion"
	 */
	protected BaseDelegatingResource() {
		propertiesIgnoredWhenUpdating.add("display");
		propertiesIgnoredWhenUpdating.add("links");
		propertiesIgnoredWhenUpdating.add(RestConstants.PROPERTY_FOR_RESOURCE_VERSION);
	}
	
	/**
	 * All our resources support letting modules register subclass handlers. If any are registered,
	 * then the resource represents a class hierarchy, e.g. requiring a "type" parameter when
	 * creating a new instance.
	 * 
	 * @return whether there are any subclass handlers registered with this resource
	 */
	public boolean hasTypesDefined() {
		return subclassHandlers != null && subclassHandlers.size() > 0;
	}
	
	/**
	 * This will be automatically called with the first call to {@link #getSubclassHandler(Class)}
	 * or {@link #getSubclassHandler(String)}. It finds all subclass handlers intended for this
	 * resource, and registers them.
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public void init() {
		List<DelegatingSubclassHandler<T, ? extends T>> tmpSubclassHandlers = new ArrayList<DelegatingSubclassHandler<T, ? extends T>>();
		
		List<DelegatingSubclassHandler> handlers = Context.getRegisteredComponents(DelegatingSubclassHandler.class);
		for (DelegatingSubclassHandler handler : handlers) {
			
			Class<? extends DelegatingSubclassHandler> handlerClass = handler.getClass();
			Class forDelegateClass = ReflectionUtil.getParameterizedTypeFromInterface(handlerClass,
			    DelegatingSubclassHandler.class, 0);
            if (forDelegateClass == null) {
                throw new IllegalStateException("Could not determine type information. Make sure that " + handlerClass.getName() + " explicitly says implements DelegatingSubclassHandler<...>. It is not sufficient to just extend a base class that implements this.");
            }
            Resource resourceForHandler = Context.getService(RestService.class)
			        .getResourceBySupportedClass(forDelegateClass);
			if (getClass().equals(resourceForHandler.getClass())) {
				SubClassHandler annotation = handlerClass.getAnnotation(SubClassHandler.class);
				if (annotation != null) {
					String[] supportedOpenmrsVersions = annotation.supportedOpenmrsVersions();
					for (String version : supportedOpenmrsVersions) {
						if (versionMatches(version)) {
							tmpSubclassHandlers.add(handler);
							break;
						}
					}
				} else {
					log.warn("SubclassHandler "
					        + handlerClass.getName()
					        + " does not have a @SubClassHandler annotation. This can cause conflicts in resolving handlers for your subclass.");
				}
			}
		}
		
		subclassHandlers = tmpSubclassHandlers;
	}
	
	private boolean versionMatches(String supportedVersion) {
		try {
			ModuleUtil.checkRequiredVersion(OpenmrsConstants.OPENMRS_VERSION_SHORT, supportedVersion);
		}
		catch (Exception e) {
			return false;
{'fraction_non_alphanumeric': 0.09158813263525305, 'fraction_numerical': 0.000837696335078534, 'mean_word_length': 5.011749895090222, 'pattern_counts': {'":': 0, '<': 36, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5634131', 'n_tokens_mistral': 4214, 'n_tokens_neox': 3878, 'n_words': 1034}