<commit_before>/**
 * Copyright 2010-2012 <NAME> <<EMAIL>>
 *
 * 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 ch.ralscha.extdirectspring.generator;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.DigestUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.FieldCallback;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.support.RequestContextUtils;

import ch.ralscha.extdirectspring.controller.RouterController;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * Generator for creating ExtJS and Touch Model objects (JS code) based on a
 * provided class or {@link ModelBean}.
 * 
 * @author <NAME>
 */
public abstract class ModelGenerator {

	private static final Map<JsCacheKey, SoftReference<String>> jsCache = new ConcurrentHashMap<JsCacheKey, SoftReference<String>>();

	private static final Map<ModelCacheKey, SoftReference<ModelBean>> modelCache = new ConcurrentHashMap<ModelCacheKey, SoftReference<ModelBean>>();

	/**
	 * Instrospects the provided class, creates a model object (JS code) and
	 * writes it into the response. Creates compressed JS code. Method ignores
	 * any validation annotations.
	 * 
	 * @param request the http servlet request
	 * @param response the http servlet response
	 * @param clazz class that the generator should introspect
	 * @param format specifies which code (ExtJS or Touch) the generator should
	 *        create.
	 * @throws IOException
	 * 
	 * @see #writeModel(HttpServletRequest, HttpServletResponse, Class,
	 *      OutputFormat, boolean)
	 */
	public static void writeModel(HttpServletRequest request, HttpServletResponse response, Class<?> clazz,
			OutputFormat format) throws IOException {
		writeModel(request, response, clazz, format, IncludeValidation.NONE, false);
	}

	/**
	 * Instrospects the provided class, creates a model object (JS code) and
	 * writes it into the response. Method ignores any validation annotations.
	 * 
	 * @param request the http servlet request
	 * @param response the http servlet response
	 * @param clazz class that the generator should introspect
	 * @param format specifies which code (ExtJS or Touch) the generator should
	 *        create
	 * @param debug if true the generator creates the output in pretty format,
	 *        false the output is compressed
	 * @throws IOException
	 */
	public static void writeModel(HttpServletRequest request, HttpServletResponse response, Class<?> clazz,
			OutputFormat format, boolean debug) throws IOException {
		writeModel(request, response, clazz, format, IncludeValidation.NONE, debug);
	}

	/**
	 * Instrospects the provided class, creates a model object (JS code) and
	 * writes it into the response.
	 * 
	 * @param request the http servlet request
	 * @param response the http servlet response
	 * @param clazz class that the generator should introspect
	 * @param format specifies which code (ExtJS or Touch) the generator should
	 *        create
	 * @param includeValidation specifies if any validation configurations
	 *        should be added to the model code
	 * @param debug if true the generator creates the output in pretty format,
	 *        false the output is compressed
	 * @throws IOException
	 */
	public static void writeModel(HttpServletRequest request, HttpServletResponse response, Class<?> clazz,
			OutputFormat format, IncludeValidation includeValidation, boolean debug) throws IOException {
		ModelBean model = createModel(clazz, includeValidation);
		writeModel(request, response, model, format, debug);
	}

	/**
	 * Creates a model object (JS code) based on the provided {@link ModelBean}
	 * and writes it into the response. Creates compressed JS code.
	 * 
	 * @param request the http servlet request
	 * @param response the http servlet response
	 * @param model {@link ModelBean} describing the model to be generated
	 * @param format specifies which code (ExtJS or Touch) the generator should
	 *        create.
	 * @throws IOException
	 */
	public static void writeModel(HttpServletRequest request, HttpServletResponse response, ModelBean model,
			OutputFormat format) throws IOException {
		writeModel(request, response, model, format, false);
	}

	/**
	 * Creates a model object (JS code) based on the provided ModelBean and
	 * writes it into the response.
	 * 
	 * @param request the http servlet request
	 * @param response the http servlet response
	 * @param model {@link ModelBean} describing the model to be generated
	 * @param format specifies which code (ExtJS or Touch) the generator should
	 *        create.
	 * @param debug if true the generator creates the output in pretty format,
	 *        false the output is compressed
	 * @throws IOException
	 */
	public static void writeModel(HttpServletRequest request, HttpServletResponse response, ModelBean model,
			OutputFormat format, boolean debug) throws IOException {

		RouterController routerController = RequestContextUtils.getWebApplicationContext(request).getBean(
				RouterController.class);

		byte[] data = generateJavascript(model, format, debug).getBytes(RouterController.UTF8_CHARSET);
		String ifNoneMatch = request.getHeader("If-None-Match");
		String etag = "\"0" + DigestUtils.md5DigestAsHex(data) + "\"";

		if (etag.equals(ifNoneMatch)) {
			response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
			return;
		}

		response.setContentType(routerController.getConfiguration().getJsContentType());
		response.setCharacterEncoding(RouterController.UTF8_CHARSET.name());
		response.setContentLength(data.length);

		response.setHeader("ETag", etag);

		@SuppressWarnings("resource")
		ServletOutputStream out = response.getOutputStream();
		out.write(data);<commit_msg>Remove dependency on RouterController's configuration. Simply set the contentType to "application/javascript"<commit_after>/**
 * Copyright 2010-2012 <NAME> <<EMAIL>>
 *
 * 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 ch.ralscha.extdirectspring.generator;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.DigestUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.FieldCallback;
import org.springframework.util.StringUtils;

import ch.ralscha.extdirectspring.controller.RouterController;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * Generator for creating ExtJS and Touch Model objects (JS code) based on a
 * provided class or {@link ModelBean}.
 * 
 * @author <NAME>
 */
public abstract class ModelGenerator {

	private static final Map<JsCacheKey, SoftReference<String>> jsCache = new ConcurrentHashMap<JsCacheKey, SoftReference<String>>();

	private static final Map<ModelCacheKey, SoftReference<ModelBean>> modelCache = new ConcurrentHashMap<ModelCacheKey, SoftReference<ModelBean>>();

	/**
	 * Instrospects the provided class, creates a model object (JS code) and
	 * writes it into the response. Creates compressed JS code. Method ignores
	 * any validation annotations.
	 * 
	 * @param request the http servlet request
	 * @param response the http servlet response
	 * @param clazz class that the generator should introspect
	 * @param format specifies which code (ExtJS or Touch) the generator should
	 *        create.
	 * @throws IOException
	 * 
	 * @see #writeModel(HttpServletRequest, HttpServletResponse, Class,
	 *      OutputFormat, boolean)
	 */
	public static void writeModel(HttpServletRequest request, HttpServletResponse response, Class<?> clazz,
			OutputFormat format) throws IOException {
		writeModel(request, response, clazz, format, IncludeValidation.NONE, false);
	}

	/**
	 * Instrospects the provided class, creates a model object (JS code) and
	 * writes it into the response. Method ignores any validation annotations.
	 * 
	 * @param request the http servlet request
	 * @param response the http servlet response
	 * @param clazz class that the generator should introspect
	 * @param format specifies which code (ExtJS or Touch) the generator should
	 *        create
	 * @param debug if true the generator creates the output in pretty format,
	 *        false the output is compressed
	 * @throws IOException
	 */
	public static void writeModel(HttpServletRequest request, HttpServletResponse response, Class<?> clazz,
			OutputFormat format, boolean debug) throws IOException {
		writeModel(request, response, clazz, format, IncludeValidation.NONE, debug);
	}

	/**
	 * Instrospects the provided class, creates a model object (JS code) and
	 * writes it into the response.
	 * 
	 * @param request the http servlet request
	 * @param response the http servlet response
	 * @param clazz class that the generator should introspect
	 * @param format specifies which code (ExtJS or Touch) the generator should
	 *        create
	 * @param includeValidation specifies if any validation configurations
	 *        should be added to the model code
	 * @param debug if true the generator creates the output in pretty format,
	 *        false the output is compressed
	 * @throws IOException
	 */
	public static void writeModel(HttpServletRequest request, HttpServletResponse response, Class<?> clazz,
			OutputFormat format, IncludeValidation includeValidation, boolean debug) throws IOException {
		ModelBean model = createModel(clazz, includeValidation);
		writeModel(request, response, model, format, debug);
	}

	/**
	 * Creates a model object (JS code) based on the provided {@link ModelBean}
	 * and writes it into the response. Creates compressed JS code.
	 * 
	 * @param request the http servlet request
	 * @param response the http servlet response
	 * @param model {@link ModelBean} describing the model to be generated
	 * @param format specifies which code (ExtJS or Touch) the generator should
	 *        create.
	 * @throws IOException
	 */
	public static void writeModel(HttpServletRequest request, HttpServletResponse response, ModelBean model,
			OutputFormat format) throws IOException {
		writeModel(request, response, model, format, false);
	}

	/**
	 * Creates a model object (JS code) based on the provided ModelBean and
	 * writes it into the response.
	 * 
	 * @param request the http servlet request
	 * @param response the http servlet response
	 * @param model {@link ModelBean} describing the model to be generated
	 * @param format specifies which code (ExtJS or Touch) the generator should
	 *        create.
	 * @param debug if true the generator creates the output in pretty format,
	 *        false the output is compressed
	 * @throws IOException
	 */
	public static void writeModel(HttpServletRequest request, HttpServletResponse response, ModelBean model,
			OutputFormat format, boolean debug) throws IOException {

		byte[] data = generateJavascript(model, format, debug).getBytes(RouterController.UTF8_CHARSET);
		String ifNoneMatch = request.getHeader("If-None-Match");
		String etag = "\"0" + DigestUtils.md5DigestAsHex(data) + "\"";

		if (etag.equals(ifNoneMatch)) {
			response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
			return;
		}

		response.setContentType("application/javascript");
		response.setCharacterEncoding(RouterController.UTF8_CHARSET.name());
		response.setContentLength(data.length);

		response.setHeader("ETag", etag);

		@SuppressWarnings("resource")
		ServletOutputStream out = response.getOutputStream();
		out.write(data);
{'fraction_non_alphanumeric': 0.08070714834742505, 'fraction_numerical': 0.002236042205296625, 'mean_word_length': 4.706539074960127, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 10}, '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': '3836443', 'n_tokens_mistral': 3837, 'n_tokens_neox': 3550, 'n_words': 1339}