/*
 * Created on Dec 27, 2006
 *
 * 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.
 *
 * Copyright @2006-2013 the original author or authors.
 */
package org.fest.assertions;

import org.fest.util.IntrospectionError;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import static java.util.Collections.emptyList;
import static org.fest.util.Lists.newArrayList;
import static org.fest.util.Preconditions.checkNotNull;
import static org.fest.util.Sets.newLinkedHashSet;

/**
 * Assertions for {@code Collection}s.
 *

 * To create a new instance of this class invoke {@link Assertions#assertThat(Collection)}.
 *
 * @author Yvonne Wang
 * @author Alex Ruiz
 */
public class CollectionAssert extends ObjectGroupAssert<CollectionAssert, Collection<?>> {
  /**
   * Creates a new {@link CollectionAssert}.
   *
   * @param actual the target to verify.
   */
  protected CollectionAssert(Collection<?> actual) {
    super(CollectionAssert.class, actual);
  }

  /**
   * Returns the number of elements in the actual collection.
   *
   * @return the number of elements in the actual collection.
   * @throws AssertionError if the actual collection is {@code null}.
   */
  @Override
  protected int actualGroupSize() {
    isNotNull();
    return actual.size();
  }

  /**
   * Creates a new instance of {@link CollectionAssert} whose target collection contains the values of the given
   * property name from the elements of this {@code CollectionAssert}'s collection. Property access works with both
   * simple properties like {@code Person.age} and nested properties {@code Person.father.age}.
   *

   * For example, let's say we have a collection of {@code Person} objects and you want to verify their age:
   *

   * assertThat(persons).onProperty("age").containsOnly(25, 16, 44, 37); // simple property
   * assertThat(persons).onProperty("father.age").containsOnly(55, 46, 74, 62); // nested property
   *

   *
   * @param propertyName the name of the property to extract values from the actual collection to build a new
   *                     {@code CollectionAssert}.
   * @return a new {@code CollectionAssert} containing the values of the given property name from the elements of this
   *         {@code CollectionAssert}'s collection.
   * @throws AssertionError       if the actual collection is {@code null}.
   * @throws NullPointerException if the given property name is {@code null}.
   * @throws IntrospectionError   if an element in the given collection does not have a matching property.
   * @since 1.3
   */
  @Override
  public @NotNull CollectionAssert onProperty(@NotNull String propertyName) {
    isNotNull();
    checkNotNull(propertyName);
    if (actual.isEmpty()) {
      return new CollectionAssert(emptyList());
    }
    return new CollectionAssert(PropertySupport.instance().propertyValues(propertyName, actual));
  }

  /**
   * {@inheritDoc}
   */
  @Override
  protected @Nullable Set<Object> actualAsSet() {
    return actual == null ? null : newLinkedHashSet(actual.toArray());
  }

  /**
   * {@inheritDoc}
   */
  @Override
  protected @Nullable List<Object> actualAsList() {
    return actual == null ? null : newArrayList(actual.toArray());
  }
}


/*
 * Created on Feb 14, 2008
 *
 * 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.
 *
 * Copyright @2008-2013 the original author or authors.
 */
package org.fest.assertions;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;

import static org.fest.assertions.ArrayInspection.copy;
import static org.fest.assertions.ErrorMessages.unexpectedEqual;
import static org.fest.assertions.ErrorMessages.unexpectedNotEqual;

/**
 * Assertions for arrays of {@code int}.
 *

 * To create a new instance of this class invoke {@link Assertions#assertThat(int[])}.
 *
 * @author Yvonne Wang
 * @author Alex Ruiz
 */
public class IntArrayAssert extends ArrayAssert<IntArrayAssert, int[]> {
  /**
   * Creates a new {@link IntArrayAssert}.
   *
   * @param actual the target to verify.
   */
  protected IntArrayAssert(@Nullable int... actual) {
    super(IntArrayAssert.class, actual);
  }

  /**
   * Verifies that the actual {@code int} array contains the given values.
   *
   * @param values the values to look for.
   * @return this assertion object.
   * @throws AssertionError       if the actual {@code int} array is {@code null}.
   * @throws NullPointerException if the given {@code int} array is {@code null}.
   * @throws AssertionError       if the actual {@code int} array does not contain the given values.
   */
  public @NotNull IntArrayAssert contains(@NotNull int... values) {
    assertContains(copy(values));
    return this;
  }

  /**
   * Verifies that the actual {@code int} array contains the given values only.
   *
   * @param values the values to look for.
   * @return this assertion object.
   * @throws AssertionError       if the actual {@code int} array is {@code null}.
   * @throws NullPointerException if the given {@code int} array is {@code null}.
   * @throws AssertionError       if the actual {@code int} array does not contain the given objects, or if the actual
   *                              {@code int} array contains elements other than the ones specified.
   */
  public @NotNull IntArrayAssert containsOnly(@NotNull int... values) {
    assertContainsOnly(copy(values));
    return this;
  }

  /**
   * Verifies that the actual {@code int} array does not contain the given values.
   *
   * @param values the values the array should exclude.
   * @return this assertion object.
   * @throws AssertionError       if the actual {@code int} array is {@code null}.
   * @throws NullPointerException if the given {@code int} array is {@code null}.
   * @throws AssertionError       if the actual {@code int} array contains any of the given values.
   */
  public @NotNull IntArrayAssert excludes(@NotNull int... values) {
    assertExcludes(copy(values));
    return this;
  }

  /**
   * Verifies that the actual {@code int} array is equal to the given array. Array equality is checked by
   * {@link Arrays#equals(int[], int[])}.
   *
   * @param expected the given array to compare the actual array to.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code int} array is not equal to the given one.
   */
  @Override
  public @NotNull IntArrayAssert isEqualTo(@Nullable int[] expected) {
    if (Arrays.equals(actual, expected)) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(unexpectedNotEqual(actual, expected));
  }

  /**
   * Verifies that the actual {@code int} array is not equal to the given array. Array equality is checked by
   * {@link Arrays#equals(int[], int[])}.
   *
   * @param array the given array to compare the actual array to.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code int} array is equal to the given one.
   */
  @Override
  public @NotNull IntArrayAssert isNotEqualTo(@Nullable int[] array) {
    if (!Arrays.equals(actual, array)) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(unexpectedEqual(actual, array));
  }
}


/*
 * Created on Dec 26, 2006
 *
 * 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.
 *
 * Copyright @2006-2013 the original author or authors.
 */
package org.fest.assertions;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static org.fest.assertions.Formatting.format;
import static org.fest.util.Preconditions.checkNotNull;

/**
 * Assertions for {@code String}s.
 * <p/>
 * To create a new instance of this class invoke {@link Assertions#assertThat(String)}.
 *
 * @author Yvonne Wang
 * @author David DIDIER
 */
public class StringAssert extends GroupAssert<StringAssert, String> {
  /**
   * Creates a new {@link StringAssert}.
   *
   * @param actual the target to verify.
   */
  protected StringAssert(@Nullable String actual) {
    super(StringAssert.class, actual);
  }

  /**
   * Verifies that the actual {@code String} is equal to the given one ignoring case.
   *
   * @param expected the given {@code String} to compare the actual {@code String} to.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code String} is {@code null}.
   * @throws AssertionError if the actual {@code String} is not equal to the given one ignoring case.
   */
  public @NotNull StringAssert isEqualToIgnoringCase(String expected) {
    if (actual == null && expected == null) {
      return this;
    }
    isNotNull();
    if (actual.equalsIgnoreCase(expected)) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(format("<%s> should be equal to :<%s> ignoring case", actual, expected));
  }

  /**
   * Returns the number of elements in the actual {@code String}.
   *
   * @return the number of elements in the actual {@code String}.
   */
  @Override
  protected int actualGroupSize() {
    isNotNull();
    return actual.length();
  }

  /**
   * Verifies that the actual {@code String} contains the given one.
   *
   * @param expected the given {@code String} expected to be contained in the actual one.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code String} is {@code null}.
   * @throws AssertionError if the actual {@code String} does not contain the given one.
   */
  public @NotNull StringAssert contains(String expected) {
    isNotNull();
    if (actual.indexOf(expected) != -1) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(format("<%s> should contain the String:<%s>", actual, expected));
  }

  /**
   * Verifies that the actual {@code String} ends with the given one.
   *
   * @param expected the given {@code String} expected to be at the end of the actual one.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code String} is {@code null}.
   * @throws AssertionError if the actual {@code String} does not end with the given one.
   */
  public @NotNull StringAssert endsWith(String expected) {
    isNotNull();
    if (actual.endsWith(expected)) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(format("<%s> should end with:<%s>", actual, expected));
  }

  /**
   * Verifies that the actual {@code String} starts with the given one.
   *
   * @param expected the given {@code String} expected to be at the beginning of the actual one.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code String} is {@code null}.
   * @throws AssertionError if the actual {@code String} does not start with the given one.
   */
  public @NotNull StringAssert startsWith(String expected) {
    isNotNull();
    if (actual.startsWith(expected)) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(format("<%s> should start with:<%s>", actual, expected));
  }

  /**
   * Verifies that the actual {@code String} does not contains the given one.
   *
   * @param s the given {@code String} expected not to be contained in the actual one.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code String} is {@code null}.
   * @throws AssertionError if the actual {@code String} does contain the given one.
   */
  public @NotNull StringAssert excludes(String s) {
    isNotNull();
    if (actual.indexOf(s) == -1) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(format("<%s> should not contain the String:<%s>", actual, s));
  }

  /**
   * Verifies that the actual {@code String} matches the given one.
   *
   * @param regex the given regular expression expected to be matched by the actual one.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code String} is {@code null}.
   * @throws AssertionError if the actual {@code String} does not match the given regular expression.
   */
  public @NotNull StringAssert matches(String regex) {
    isNotNull();
    if (actual.matches(regex)) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(format("<%s> should match the regular expression:<%s>", actual, regex));
  }

  /**
   * Verifies that the actual {@code String} does not match the given one.
   *
   * @param regex the given regular expression expected not to be matched by the actual one.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code String} is {@code null}.
   * @throws AssertionError if the actual {@code String} matches the given regular expression.
   */
  public @NotNull StringAssert doesNotMatch(String regex) {
    isNotNull();
    if (!actual.matches(regex)) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(format("<%s> should not match the regular expression:<%s>", actual, regex));
  }

  /**
   * Verifies that the actual {@code String} contains the given text regardless of the case.
   *
   * @param text the given text.
   * @return this assertion object.
   * @throws AssertionError       if the actual {@code String} is {@code null}.
   * @throws AssertionError       if the actual {@code String} does not contain the given text.
   * @throws NullPointerException if the given {@code String} is {@code null}.
   * @since 1.3
   */
  public @NotNull StringAssert containsIgnoringCase(@NotNull String text) {
    checkNotNull(text);
    isNotNull();
    if (actual.toLowerCase().contains(text.toLowerCase())) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(format("<%s> does not contain <%s>", actual, text));
  }

  /**
   * Verifies that the actual {@code String} does not contain the given text.
   *
   * @param text the given text.
   * @return this assertion object.
   * @throws AssertionError       if the actual {@code String} is {@code null}.
   * @throws AssertionError       if the actual {@code String} contains the given text.
   * @throws NullPointerException if the given {@code String} is {@code null}.
   * @since 1.3
   */
  public @NotNull StringAssert doesNotContain(@NotNull String text) {
    checkNotNull(text);
    isNotNull();
    if (!actual.contains(text)) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(format("<%s> should not contain <%s>", actual, text));
  }
}


/*
 * Created on Jun 18, 2007
 *
 * 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.
 *
 * Copyright @2007-2013 the original author or authors.
 */
package org.fest.assertions;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static java.lang.Float.compare;
import static java.lang.Float.valueOf;
import static java.lang.Math.abs;
import static org.fest.assertions.ErrorMessages.*;
import static org.fest.assertions.Formatting.format;

/**
 * Assertions for {@code Float}s and {@code float}s.
 * <p/>
 * To create a new instance of this class invoke either {@link Assertions#assertThat(Float)} or
 * {@link Assertions#assertThat(float)}.
 *
 * @author Yvonne Wang
 * @author Alex Ruiz
 * @author Ansgar Konermann
 */
public class FloatAssert extends GenericAssert<FloatAssert, Float> implements NumberAssert {
  private static final float ZERO = 0f;

  /**
   * Creates a new {@link FloatAssert}.
   *
   * @param actual the actual value to verify.
   */
  protected FloatAssert(float actual) {
    super(FloatAssert.class, actual);
  }

  /**
   * Creates a new {@link FloatAssert}.
   *
   * @param actual the actual value to verify.
   */
  protected FloatAssert(@Nullable Float actual) {
    super(FloatAssert.class, actual);
  }

  /**
   * Creates a new holder for a delta value to be used in
   * {@link FloatAssert#isEqualTo(float, org.fest.assertions.FloatAssert.Delta)}.
   *
   * @param d the delta value.
   * @return a new delta value holder.
   * @deprecated use method {@link org.fest.assertions.Delta#delta(double)} instead. This method will be removed in
   *             version 2.0.
   */
  @Deprecated
  public static @NotNull Delta delta(float d) {
    return new Delta(d);
  }

  /**
   * Verifies that the actual {@code Float} is equal to the given one.
   *
   * @param expected the value to compare the actual one to.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Float} is not equal to the given one.
   */
  public @NotNull FloatAssert isEqualTo(float expected) {
    return isEqualTo(valueOf(expected));
  }

  /**
   * Verifies that the actual {@code Float} is equal to the given one, within a positive delta.
   *
   * @param expected the value to compare the actual one to.
   * @param delta    the given delta.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Float} is not equal to the given one.
   * @deprecated use method {@link #isEqualTo(float, org.fest.assertions.Delta)} instead. This method will be removed in
   *             version 2.0.
   */
  @Deprecated
  public @NotNull FloatAssert isEqualTo(float expected, @NotNull Delta delta) {
    return isEqualTo(expected, delta.value);
  }

  /**
   * Verifies that the actual {@code Float} is equal to the given one, within a positive delta.
   *
   * @param expected the value to compare the actual one to.
   * @param delta    the given delta.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Float} is not equal to the given one.
   * @since 1.2
   */
  public @NotNull FloatAssert isEqualTo(float expected, @NotNull org.fest.assertions.Delta delta) {
    return isEqualTo(expected, delta.floatValue());
  }

  private @NotNull FloatAssert isEqualTo(float expected, float deltaValue) {
    return isEqualTo(valueOf(expected), deltaValue);
  }

  /**
   * Verifies that the actual {@code Float} is equal to the given one, within a positive delta.
   *
   * @param expected the value to compare the actual one to.
   * @param delta    the given delta.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Float} is not equal to the given one.
   * @since 1.3
   */
  public @NotNull FloatAssert isEqualTo(@Nullable Float expected, @NotNull org.fest.assertions.Delta delta) {
    return isEqualTo(expected, delta.floatValue());
  }

  private @NotNull FloatAssert isEqualTo(@Nullable Float expected, float deltaValue) {
    if (actual == null || expected == null) {
      return isEqualTo(expected);
    }
    if (actual.compareTo(expected) == 0) {
      return this;
    }
    if (abs(expected - actual) <= deltaValue) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(unexpectedNotEqual(actual, expected) + format(" using delta:<%s>", deltaValue));
  }

  /**
   * Verifies that the actual {@code Float} is not equal to the given one.
   *
   * @param other the given value.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Float} is equal to the given one.
   */
  public @NotNull FloatAssert isNotEqualTo(float other) {
    if (compareTo(other) != 0) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(unexpectedEqual(actual, other));
  }

  /**
   * Verifies that the actual {@code Float} is greater than the given one.
   *
   * @param other the given value.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Float} is not greater than the given one.
   */
  public @NotNull FloatAssert isGreaterThan(float other) {
    if (compareTo(other) > 0) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(unexpectedLessThanOrEqualTo(actual, other));
  }

  /**
   * Verifies that the actual {@code Float} is less than the given one.
   *
   * @param other the given value.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Float} is not less than the given one.
   */
  public @NotNull FloatAssert isLessThan(float other) {
    if (compareTo(other) < 0) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(unexpectedGreaterThanOrEqualTo(actual, other));
  }

  /**
   * Verifies that the actual {@code Float} is greater or equal to the given one.
   *
   * @param other the given value.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Float} is not greater than or equal to the given one.
   */
  public @NotNull FloatAssert isGreaterThanOrEqualTo(float other) {
    if (compareTo(other) >= 0) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(unexpectedLessThan(actual, other));
  }

  /**
   * Verifies that the actual {@code Float} is less or equal to the given one.
   *
   * @param other the given value.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Float} is not less than or equal to the given one.
   */
  public @NotNull FloatAssert isLessThanOrEqualTo(float other) {
    if (compareTo(other) <= 0) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(unexpectedGreaterThan(actual, other));
  }

  private int compareTo(float other) {
    return compare(actual, other);
  }

  /**
   * Verifies that the actual {@code Float} is equal to {@link Float#NaN}.
   *
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Float} is not equal to {@code NaN}.
   */
  public @NotNull FloatAssert isNaN() {
    return isEqualTo(Float.NaN);
  }

  /**
   * Verifies that the actual {@code Float} is equal to zero.
   *
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Float} is not equal to zero.
   */
  @Override
  public @NotNull FloatAssert isZero() {
    return isEqualTo(ZERO);
  }

  /**
   * Verifies that the actual {@code Float} is positive.
   *
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Float} is not positive.
   */
  @Override
  public @NotNull FloatAssert isPositive() {
    return isGreaterThan(ZERO);
  }

  /**
   * Verifies that the actual {@code Float} is negative.
   *
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Float} is not negative.
   */
  @Override
  public @NotNull FloatAssert isNegative() {
    return isLessThan(ZERO);
  }

  /**
   * Holds a delta value to be used in {@link FloatAssert#isEqualTo(float, org.fest.assertions.FloatAssert.Delta)}.
   *
   * @deprecated use top-level class {@link org.fest.assertions.Delta} instead. This class will be removed in version
   *             2.0.
   */
  @Deprecated
  public static class Delta {
    final float value;

    private Delta(float value) {
      this.value = value;
    }
  }
}


/*
 * Created on Oct 2, 2009
 *
 * 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.
 *
 * Copyright @2009-2013 the original author or authors.
 */
package org.fest.assertions;

import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import static java.lang.reflect.Array.get;
import static java.lang.reflect.Array.getLength;
import static org.fest.util.Lists.newArrayList;
import static org.fest.util.Preconditions.checkNotNull;
import static org.fest.util.Sets.newLinkedHashSet;

/**
 * Utility methods for arrays.
 *
 * @author Alex Ruiz
 * @since 1.2
 */
public final class ArrayInspection {
  private ArrayInspection() {
  }

  /**
   * Copies the contents of the given array into an array of objects.
   *
   * @param array the array to copy.
   * @return an array of objects containing the contents of the array.
   * @throws NullPointerException     if the given object is {@code null}.
   * @throws IllegalArgumentException if the given object is not an array.
   */
  public static @NotNull Object[] copy(@NotNull Object array) {
    return copyToList(checkNotNull(array)).toArray();
  }

  /**
   * Copies the contents of the given array into a list.
   *
   * @param array the array to copy.
   * @return a list containing the contents of the array.
   * @throws IllegalArgumentException if the given object is not an array.
   * @since 1.3.
   */
  public static @NotNull List<Object> copyToList(@NotNull Object array) {
    return copy(checkNotNull(array), newArrayList());
  }

  /**
   * Copies the contents of the given array into a list.
   *
   * @param array the array to copy.
   * @return a list containing the contents of the array.
   * @throws IllegalArgumentException if the given object is not an array.
   * @since 1.3.
   */
  public static @NotNull Set<Object> copyToSet(@NotNull Object array) {
    return copy(checkNotNull(array), newLinkedHashSet());
  }

  private static @NotNull <T extends Collection<Object>> T copy(@NotNull Object array, @NotNull T destination) {
    int length = sizeOf(array);
    for (int i = 0; i < length; i++) {
      destination.add(get(array, i));
    }
    return destination;
  }

  /**
   * Returns the size of the given array.
   *
   * @param array the array.
   * @return the size of the given array.
   * @throws NullPointerException     if the given array is {@code null}.
   * @throws IllegalArgumentException if the given object is not an array.
   */
  public static int sizeOf(@NotNull Object array) {
    checkNotNull(array);
    validateIsArray(array);
    return getLength(array);
  }

  private static void validateIsArray(@NotNull Object array) {
    if (!array.getClass().isArray()) {
      throw new IllegalArgumentException("The given object is not an array");
    }
  }
}


/*
 * Created on Jun 14, 2007
 *
 * 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.
 *
 * Copyright @2007-2013 the original author or authors.
 */
package org.fest.assertions;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static java.lang.Integer.valueOf;
import static org.fest.assertions.ErrorMessages.*;

/**
 * Assertions for {@code Integer}s and {@code int}s.
 * <p/>
 * To create a new instance of this class invoke either {@link Assertions#assertThat(Integer)} or
 * {@link Assertions#assertThat(int)}.
 *
 * @author Yvonne Wang
 * @author David DIDIER
 * @author Ansgar Konermann
 * @author Alex Ruiz
 */
public class IntAssert extends GenericAssert<IntAssert, Integer> implements NumberAssert {
  private static final int ZERO = 0;

  /**
   * Creates a new {@link IntAssert}.
   *
   * @param actual the actual value to verify.
   */
  protected IntAssert(int actual) {
    super(IntAssert.class, actual);
  }

  /**
   * Creates a new {@link IntAssert}.
   *
   * @param actual the actual value to verify.
   */
  protected IntAssert(@Nullable Integer actual) {
    super(IntAssert.class, actual);
  }

  /**
   * Verifies that the actual {@code Integer} is equal to the given one.
   *
   * @param expected the value to compare the actual one to.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Integer} is not equal to the given one.
   */
  public @NotNull IntAssert isEqualTo(int expected) {
    return isEqualTo(valueOf(expected));
  }

  /**
   * Verifies that the actual {@code Integer} is not equal to the given one.
   *
   * @param other the given value.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Integer} is equal to the given one.
   */
  public @NotNull IntAssert isNotEqualTo(int other) {
    return isNotEqualTo(valueOf(other));
  }

  /**
   * Verifies that the actual {@code Integer} is greater than the given one.
   *
   * @param other the given value.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Integer} is not greater than the given one.
   */
  public @NotNull IntAssert isGreaterThan(int other) {
    if (actual > other) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(unexpectedLessThanOrEqualTo(actual, other));
  }

  /**
   * Verifies that the actual {@code Integer} is less than the given one.
   *
   * @param other the given value.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Integer} is not less than the given one.
   */
  public @NotNull IntAssert isLessThan(int other) {
    if (actual < other) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(unexpectedGreaterThanOrEqualTo(actual, other));
  }

  /**
   * Verifies that the actual {@code Integer} is greater or equal to the given one.
   *
   * @param other the given value.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Integer} is not greater than or equal to the given one.
   */
  public @NotNull IntAssert isGreaterThanOrEqualTo(int other) {
    if (actual >= other) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(unexpectedLessThan(actual, other));
  }

  /**
   * Verifies that the actual {@code Integer} is less or equal to the given one.
   *
   * @param other the given value.
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Integer} is not less than or equal to the given one.
   */
  public @NotNull IntAssert isLessThanOrEqualTo(int other) {
    if (actual <= other) {
      return this;
    }
    failIfCustomMessageIsSet();
    throw failure(unexpectedGreaterThan(actual, other));
  }

  /**
   * Verifies that the actual {@code Integer} is equal to zero.
   *
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Integer} is not equal to zero.
   */
  @Override
  public @NotNull IntAssert isZero() {
    return isEqualTo(ZERO);
  }

  /**
   * Verifies that the actual {@code Integer} is positive.
   *
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Integer} is not positive.
   */
  @Override
  public @NotNull IntAssert isPositive() {
    return isGreaterThan(ZERO);
  }

  /**
   * Verifies that the actual {@code Integer} is negative.
   *
   * @return this assertion object.
   * @throws AssertionError if the actual {@code Integer} is not negative.
   */
  @Override
  public @NotNull IntAssert isNegative() {
    return isLessThan(ZERO);
  }
}


/*
 * Copyright 2011 Roberto Tyley
 *
 *    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 com.madgag.android.listviews;

import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import java.util.Arrays;
import java.util.List;

import static java.util.Arrays.asList;

public class ViewHoldingListAdapter<T> extends BaseAdapter {

	private List<T> itemList;
    private final ViewFactory<T> viewFactory, dropDownViewFactory;

    public ViewHoldingListAdapter(List<T> itemList, ViewFactory<T> viewFactory, ViewFactory<T> dropDownViewFactory) {
        this.itemList = itemList;
        this.viewFactory = viewFactory;
        this.dropDownViewFactory = dropDownViewFactory;
    }

    public ViewHoldingListAdapter(List<T> itemList, ViewFactory<T> viewFactory) {
		this(itemList, viewFactory, viewFactory);
    }

    public ViewHoldingListAdapter(List<T> itemList, ViewCreator c, ViewHolderFactory<T> vhf) {
		this(itemList, new ViewFactory<T>(c, vhf));
    }

    public ViewHoldingListAdapter(T[] items, ViewFactory<T> viewFactory) {
        this(asList(items), viewFactory);
    }

    public ViewHoldingListAdapter(T[] items, ViewCreator c, ViewHolderFactory<T> vhf) {
        this(asList(items), c, vhf);
    }

	@Override
	public boolean hasStableIds() {
		return true;
	}

	public void setList(List<T> itemList) {
		this.itemList=itemList;
		notifyDataSetChanged();
	}

	public int getCount() {
		return itemList.size();
	}

	public T getItem(int index) {
		return itemList.get(index);
	}

	public long getItemId(int i) {
		return getItem(i).hashCode();
	}

	public View getView(int index, View convertView, ViewGroup parent) {
        return viewFactory.getView(convertView, itemList.get(index));
	}

    /**
     * Declared by SpinnerAdapter, this method allows your spinner to show
     * different views in your drop down vs the 'closed' spinned box.
     */
    public View getDropDownView(int index, View convertView, ViewGroup parent) {
        return dropDownViewFactory.getView(convertView, itemList.get(index));
    }
}


/**
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   This file is part of the LDP4j Project:
 *     http://www.ldp4j.org/
 *
 *   Center for Open Middleware
 *     http://www.centeropenmiddleware.com/
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Copyright (C) 2014-2016 Center for Open Middleware.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   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.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Artifact    : org.ldp4j.framework:ldp4j-application-api:0.2.2
 *   Bundle      : ldp4j-application-api-0.2.2.jar
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 */
package org.ldp4j.application.vocabulary;

import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;

import static java.util.Objects.*;

/**
 * A base vocabulary implementation for creating immutable vocabularies that
 * defines a collection of {@code ImmutableTerm}s.

 * Purpose specific vocabularies should be implemented as follows:
 *
 *

 * private static class CustomVocabulary extends
 * 		AbstractImmutableVocabulary<ImmutableTerm> {
 *
 * 	private static final String NAMESPACE = "http://www.example.org/vocab";
 * 	private static final String PREFERRED_PREFIX = "test";
 *
 * 	private static final String TERM_THREE = "termThree";
 * 	private static final String TERM_TWO = "termTwo";
 * 	private static final String TERM_ONE = "termOne";
 *
 * 	public CustomVocabulary() {
 * 		super(ImmutableTerm.class, NAMESPACE, PREFERRED_PREFIX);
 * 	}
 *
 * 	private static final CustomVocabulary VOCABULARY;
 * 	private static final Term ONE;
 * 	private static final Term TWO;
 * 	private static final Term THREE;
 *
 * 	static {
 * 		VOCABULARY = new CustomVocabulary();
 * 		ONE = new ImmutableTerm(VOCABULARY, TERM_ONE);
 * 		TWO = new ImmutableTerm(VOCABULARY, TERM_TWO);
 * 		THREE = new ImmutableTerm(VOCABULARY, TERM_THREE);
 * 		VOCABULARY.initialize();
 * 	}
 * }
 *

 *
 * Term related operations will fail with a {@code IllegalStateException} if
 * they are used before the vocabulary is initialized properly.
 *
 * @version 1.0
 * @since 1.0.0
 * @author Miguel Esteban Gutiérrez
 * @see ImmutableTerm
 */
public abstract class AbstractImmutableVocabulary<T extends ImmutableTerm> implements Vocabulary {

	private static final long serialVersionUID = -6913490730122202939L;

	private enum Status {
		INITIALIZING("is already initialized"),
		INITIALIZED("has not been initialized properly"),
		;
		private final String explanation;

		Status(String explanation) {
			this.explanation = explanation;
		}

		String getFailure(String namespace) {
			return "Vocabulary '"+namespace+"' "+explanation;
		}

	}

	private final UUID id=UUID.randomUUID();

	private final String namespace;
	private final String prefix;
	private final Class<T> termClass;

	private final Map<String,Integer> nameOrdinal=new HashMap<String,Integer>(); // NOSONAR
	private final SortedMap<Integer,T> terms=new TreeMap<Integer,T>(); // NOSONAR

	private int ordinal=-1;

	private Status status=Status.INITIALIZING;

	/**
	 * Create a new instance with a term class, a namespace, and a preferred
	 * prefix.
	 *
	 * @param clazz
	 *            the type of terms held by the vocabulary.
	 * @param namespace
	 *            the namespace of the vocabulary.
	 * @param prefix
	 *            the preferred prefix of the vocabulary.
	 * @throws NullPointerException
	 *             if any of the parameters is {@code null}.
	 */
	public AbstractImmutableVocabulary(Class<T> clazz, String namespace, String prefix) {
		this.termClass = Objects.requireNonNull(clazz,"Term class cannot be null");
		this.namespace = Objects.requireNonNull(namespace,"Namespace cannot be null");
		this.prefix = Objects.requireNonNull(prefix,"Preferred prefix cannot be null");
	}

	private void checkStatus(Status status) {
		if(!this.status.equals(status)) {
			throw new IllegalStateException(status.getFailure(this.namespace));
		}
	}

	private void checkInitializationPrecondition(boolean precondition, String message, Object... args) {
		if(!precondition) {
			String failureHeader=
				String.format(
					"Vocabulary '%s' (%s) initialization failure: ",
					this.namespace,
					getClass().getName());
			throw new IllegalArgumentException(failureHeader.concat(String.format(message,args)));
		}
	}

	/**
	 * Get the unique identifier of the vocabulary.
	 *
	 * @return The identifier of the vocabulary.
	 * @see java.util.UUID
	 */
	public final UUID getId() {
		return this.id;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public final String getNamespace() {
		return this.namespace;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public final String getPreferredPrefix() {
		return this.prefix;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public final T[] terms() {
		checkStatus(Status.INITIALIZED);
		@SuppressWarnings("unchecked")
		T[] array=(T[])Array.newInstance(this.termClass,this.ordinal);
		return this.terms.values().toArray(array);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public final int size() {
		checkStatus(Status.INITIALIZED);
		return this.ordinal+1;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public final T fromName(String name) {
		checkStatus(Status.INITIALIZED);
		requireNonNull(name,"Term name cannot be null");
		Integer termOrdinal = this.nameOrdinal.get(name);
		if(termOrdinal!=null) {
			return this.terms.get(termOrdinal);
		}
		return null;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public T fromOrdinal(int ordinal) {
		checkStatus(Status.INITIALIZED);
		if(ordinal<0 || this.ordinal<ordinal) {
			throw new IndexOutOfBoundsException("No term available with ordinal '"+ordinal+"'");
		}
		return this.terms.get(ordinal);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public final <V> T fromValue(V value) {
		checkStatus(Status.INITIALIZED);
		try {
			@SuppressWarnings("unchecked")
			TypeAdapter<T,V> adapter = (TypeAdapter<T, V>) TypeAdapter.createAdapter(this.termClass,value.getClass());
			for(T candidate:this.terms.values()) {
				if(value.equals(adapter.adapt(candidate))) {
					return candidate;
				}
			}
			return null;
		} catch (CannotAdaptClassesException e) {
			throw new UnsupportedOperationException("Class '"+this.termClass.getCanonicalName()+" cannot be transformed to '"+value.getClass().getCanonicalName()+"'",e);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public final Iterator<Term> iterator() {
		checkStatus(Status.INITIALIZED);
		final Iterator<? extends Term> iterator = this.terms.values().iterator();
		return new Iterator<Term>() {
			@Override
			public boolean hasNext() {
				return iterator.hasNext();
			}

			@Override
			public Term next() {
				return iterator.next();
			}

			@Override
			public void remove() {
				throw new UnsupportedOperationException("Removal not supported");
			}
		};
	}

	/**
	 * Allow the reservation of term names during the initialization of the
	 * vocabulary.
	 *
	 * @param name
	 *            then name of the term
	 * @return a number that represents the position in which the term was
	 *         reserved
	 * @throws IllegalArgumentException
	 *             if the specified name is not valid or it has been already
	 *             reserved.
	 * @throws IllegalStateException
	 *             if the vocabulary has been already initialized.
	 */
	protected final int reserveTermName(String name) {
		checkStatus(Status.INITIALIZING);
		checkInitializationPrecondition(TermUtils.isValidTermName(name), "Object '%s' is not a valid term name",name);
		checkInitializationPrecondition(!this.nameOrdinal.containsKey(name),"Term '%s' has been already reserved",name);
		this.nameOrdinal.put(name, ++this.ordinal);
		return this.ordinal;
	}

	/**
	 * Upon reservation, the method enables registering the properly built
	 * immutable term instance.
	 *
	 * @param term
	 *            the term to be registered.
	 * @throws IllegalArgumentException
	 *             if the specified term instance cannot be registered, either
	 *             because the ordinal is invalid or because another term
	 *             with the same name has already been registered.
	 * @throws IllegalStateException
	 *             if the vocabulary has been already initialized.
	 */
	protected final <S extends ImmutableTerm> void registerTerm(S term) {
		checkStatus(Status.INITIALIZING);
		checkInitializationPrecondition(this.nameOrdinal.containsKey(term.name()),"Term '%s' has not been reserved",term.name());
		checkInitializationPrecondition(term.ordinal()>=0 && term.ordinal()<=this.ordinal,"Invalid ordinal '%d' for reserved name '%s'",term.ordinal(),term.name());
		this.terms.put(term.ordinal(),this.termClass.cast(term));
	}

	/**
	 * Complete the initialization of the vocabulary. Beyond this point the
	 * vocabulary can be put to use.
	 *
	 * @throws IllegalStateException
	 *             if the vocabulary has been already initialized or not all the
	 *             reserved names have been registered.
	 */
	protected final void initialize() {
		checkStatus(Status.INITIALIZING);
		if(this.terms.size()!=this.nameOrdinal.size()) {
			throw new IllegalStateException(
				String.format(
					"Vocabulary '%s' (%s) initialization failure: not all reserved names have been registered",
					this.namespace,
					getClass().getName()));
		}
		this.status=Status.INITIALIZED;
	}

}


/**
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   This file is part of the LDP4j Project:
 *     http://www.ldp4j.org/
 *
 *   Center for Open Middleware
 *     http://www.centeropenmiddleware.com/
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Copyright (C) 2014-2016 Center for Open Middleware.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   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.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Artifact    : org.ldp4j.framework:ldp4j-application-kernel-jpa:0.2.2
 *   Bundle      : ldp4j-application-kernel-jpa-0.2.2.jar
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 */
package org.ldp4j.application.kernel.persistence.jpa;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

import java.net.URI;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import org.ldp4j.application.data.constraints.Constraints;
import org.ldp4j.application.engine.context.HttpRequest;
import org.ldp4j.application.kernel.constraints.ConstraintReport;
import org.ldp4j.application.kernel.constraints.ConstraintReportId;
import org.ldp4j.application.kernel.resource.Attachment;
import org.ldp4j.application.kernel.resource.Resource;
import org.ldp4j.application.kernel.resource.ResourceId;
import org.ldp4j.application.kernel.resource.ResourceVisitor;
import org.ldp4j.application.kernel.resource.Resources;
import org.ldp4j.application.kernel.template.AttachedTemplate;
import org.ldp4j.application.kernel.template.ResourceTemplate;
import org.ldp4j.application.kernel.template.TemplateIntrospector;

import com.google.common.base.MoreObjects.ToStringHelper;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

class JPAResource extends AbstractJPAResource implements Resource {

	/**
	 * Persistent key required by JPA
	 */
	private long primaryKey;

	/**
	 * Not final to enable its usage in JPA
	 */
	private List<JPAAttachment> attachments;

	/**
	 * Not final to enable its usage in JPA
	 */
	private Set<String> failures;

	/**
	 * Not final to enable its usage in JPA
	 */
	private ResourceId id;

	/**
	 * Not final to enable its usage in JPA
	 */
	private ResourceId parentId;

	private URI indirectId;

	private final AttachmentCollection attachmentCollection;

	protected JPAResource() {
		this.attachmentCollection=new AttachmentCollection();
		this.failures=Sets.newLinkedHashSet();
		this.attachments=Lists.newArrayList();
	}

	protected JPAResource(ResourceId id, ResourceId parentId) {
		this();
		this.id=id;
		this.parentId = parentId;
	}

	protected JPAResource(ResourceId id) {
		this(id,null);
	}

	@Override
	protected void init() {
		ResourceTemplate template = super.getTemplate(this.id);
		Set<AttachedTemplate> attachedTemplates = template.attachedTemplates();
		if(!attachedTemplates.isEmpty() && this.attachments.isEmpty()) {
			for(AttachedTemplate attachedTemplate:attachedTemplates) {
				JPAAttachment newAttachment = new JPAAttachment(attachedTemplate.id());
				this.attachments.add(newAttachment);
			}
		}
		this.attachmentCollection.init(this.attachments);
	}

	protected final JPAResource createChild(ResourceId resourceId, ResourceTemplate template) {
		JPAResource newResource=null;
		if(!TemplateIntrospector.newInstance(template).isContainer()) {
			newResource=new JPAResource(resourceId,this.id);
		} else {
			newResource=new JPAContainer(resourceId,this.id);
		}
		newResource.setTemplateLibrary(getTemplateLibrary());
		return newResource;
	}

	private synchronized ConstraintReportId nextConstraintReportId() {
		String failureId=null;
		do {
			failureId=UUID.randomUUID().toString();
		} while(this.failures.contains(failureId));
		ConstraintReportId reportId=ConstraintReportId.create(this.id, failureId);
		this.failures.add(failureId);
		return reportId;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourceId id() {
		return this.id;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setIndirectId(URI indirectId) {
		this.indirectId=indirectId;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public URI indirectId() {
		return this.indirectId;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean isRoot() {
		return this.parentId==null;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourceId parentId() {
		return this.parentId;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Attachment findAttachment(ResourceId resourceId) {
		checkNotNull(resourceId,"Attached resource identifier cannot be null");
		return this.attachmentCollection.attachmendByResourceId(resourceId);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Resource attach(String attachmentId, ResourceId resourceId) {
		return attach(attachmentId,resourceId,Resource.class);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public <T extends Resource> T attach(String attachmentId, ResourceId resourceId, Class<? extends T> clazz) {
		checkNotNull(attachmentId,"Attachment identifier cannot be null");
		checkNotNull(resourceId,"Attached resource identifier cannot be null");
		checkNotNull(clazz,"Attached resource class cannot be null");
		this.attachmentCollection.checkNotAttached(attachmentId,resourceId);
		ResourceTemplate attachmentTemplate=super.getTemplate(resourceId);
		checkState(Resources.areCompatible(clazz,attachmentTemplate),"Attachment '%s' is not of type '%s' (%s)",attachmentId,clazz.getCanonicalName(),attachmentTemplate.getClass().getCanonicalName());
		JPAResource newResource=createChild(resourceId,attachmentTemplate);
		JPAAttachment newAttachment=this.attachmentCollection.attachmentById(attachmentId);
		newAttachment.bind(resourceId);
		return clazz.cast(newResource);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean detach(Attachment attachment) {
		return this.attachmentCollection.removeAttachment(attachment);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Set<JPAAttachment> attachments() {
		return ImmutableSet.copyOf(this.attachments);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void accept(ResourceVisitor visitor) {
		visitor.visitResource(this);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ConstraintReport addConstraintReport(Constraints constraints, Date date, HttpRequest request) {
		ConstraintReportId reportId = nextConstraintReportId();
		return new JPAConstraintReport(reportId,date, request, constraints);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Set<ConstraintReportId> constraintReports() {
		Set<String> currentFailures=null;
		synchronized(this) {
			currentFailures=ImmutableSet.copyOf(this.failures);
		}
		Builder<ConstraintReportId> builder=ImmutableSet.builder();
		for(String failure:currentFailures) {
			builder.add(ConstraintReportId.create(this.id,failure));
		}
		return builder.build();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void removeFailure(ConstraintReport report) {
		if(report!=null) {
			String failureId = report.id().failureId();
			synchronized(this) {
				this.failures.remove(failureId);
			}
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String toString() {
		return stringHelper().toString();
	}

	@Override
	protected ToStringHelper stringHelper() {
		return
			super.stringHelper().
				add("primaryKey",this.primaryKey).
				add("id",this.id).
				add("parentId",this.parentId).
				add("attachments",this.attachments).
				add("failures", this.failures);
	}

}


/**
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   This file is part of the LDP4j Project:
 *     http://www.ldp4j.org/
 *
 *   Center for Open Middleware
 *     http://www.centeropenmiddleware.com/
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Copyright (C) 2014-2016 Center for Open Middleware.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   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.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Artifact    : org.ldp4j.framework:ldp4j-application-kernel-jpa:0.2.2
 *   Bundle      : ldp4j-application-kernel-jpa-0.2.2.jar
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 */
package org.ldp4j.application.kernel.persistence.jpa;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

import java.util.Date;

import org.ldp4j.application.engine.context.EntityTag;
import org.ldp4j.application.kernel.endpoint.Endpoint;
import org.ldp4j.application.kernel.resource.ResourceId;

import com.google.common.base.MoreObjects;

final class JPAEndpoint implements Endpoint {

	/**
	 * Not final to enable its usage in JPA
	 */
	private String path;

	/**
	 * Not final to enable its usage in JPA
	 */
	private Date created;

	/**
	 * Surrogate object to guarantee DB portability
	 */
	private Key resourceId;

	private EntityTag entityTag;
	private Date lastModified;
	private Date deleted;

	private JPAEndpoint() {
		// JPA Friendly
	}

	private JPAEndpoint(String path, ResourceId resourceId, Date created, EntityTag entityTag) {
		this.path = path;
		this.resourceId = Key.newInstance(resourceId);
		this.created = created;
		this.entityTag = entityTag;
		this.lastModified = created;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String path() {
		return this.path;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Date created() {
		return this.created;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Date deleted() {
		return this.deleted;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public EntityTag entityTag() {
		return this.entityTag;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Date lastModified() {
		return this.lastModified;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ResourceId resourceId() {
		return this.resourceId.resourceId();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void modify(EntityTag newEntityTag, Date newLastModified) {
		checkState(this.deleted==null,"Endpoint is already deleted");
		this.entityTag=newEntityTag;
		this.lastModified=new Date(newLastModified.getTime());
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void delete(Date deleted) {
		checkState(this.deleted==null,"Endpoint is already deleted");
		this.deleted=deleted;
		this.resourceId=null;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String toString() {
		return
			MoreObjects.
				toStringHelper(getClass()).
					omitNullValues().
					add("path",this.path).
					add("created",this.created).
					add("deleted",this.deleted).
					add("entityTag",this.entityTag).
					add("lastModified",this.lastModified.getTime()).
					add("resourceId",this.resourceId).
					toString();
	}

	static JPAEndpoint create(String path, ResourceId resourceId, Date created, EntityTag entityTag) {
		checkNotNull(path,"Endpoint path cannot be null");
		checkNotNull(resourceId,"Endpoint identifier cannot be null");
		checkNotNull(created,"Endpoint creation date cannot be null");
		checkNotNull(entityTag,"Endpoint entity tag cannot be null");
		return new JPAEndpoint(path, resourceId, created, entityTag);
	}

}


/**
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   This file is part of the LDP4j Project:
 *     http://www.ldp4j.org/
 *
 *   Center for Open Middleware
 *     http://www.centeropenmiddleware.com/
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Copyright (C) 2014-2016 Center for Open Middleware.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   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.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Artifact    : org.ldp4j.framework:ldp4j-application-kernel-core:0.2.2
 *   Bundle      : ldp4j-application-kernel-core-0.2.2.jar
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 */
package org.ldp4j.application.kernel.engine;

import static com.google.common.base.Preconditions.checkState;

import java.util.Date;

import org.ldp4j.application.data.DataSet;
import org.ldp4j.application.data.ManagedIndividualId;
import org.ldp4j.application.engine.ApplicationContextCreationException;
import org.ldp4j.application.engine.context.ApplicationContext;
import org.ldp4j.application.engine.context.ApplicationContextException;
import org.ldp4j.application.engine.context.ApplicationContextOperation;
import org.ldp4j.application.engine.context.ApplicationExecutionException;
import org.ldp4j.application.engine.context.Capabilities;
import org.ldp4j.application.engine.context.HttpRequest;
import org.ldp4j.application.engine.context.InvalidIndirectIdentifierException;
import org.ldp4j.application.engine.context.PublicResource;
import org.ldp4j.application.engine.lifecycle.ApplicationLifecycleListener;
import org.ldp4j.application.ext.Application;
import org.ldp4j.application.ext.ApplicationRuntimeException;
import org.ldp4j.application.ext.Configuration;
import org.ldp4j.application.ext.Deletable;
import org.ldp4j.application.ext.InvalidContentException;
import org.ldp4j.application.ext.Modifiable;
import org.ldp4j.application.ext.Namespaces;
import org.ldp4j.application.ext.Query;
import org.ldp4j.application.ext.Queryable;
import org.ldp4j.application.ext.ResourceHandler;
import org.ldp4j.application.kernel.constraints.ConstraintReport;
import org.ldp4j.application.kernel.constraints.ConstraintReportId;
import org.ldp4j.application.kernel.constraints.ConstraintReportRepository;
import org.ldp4j.application.kernel.constraints.ConstraintReportTransformer;
import org.ldp4j.application.kernel.endpoint.Endpoint;
import org.ldp4j.application.kernel.endpoint.EndpointRepository;
import org.ldp4j.application.kernel.resource.Container;
import org.ldp4j.application.kernel.resource.FeatureExecutionException;
import org.ldp4j.application.kernel.resource.FeaturePostconditionException;
import org.ldp4j.application.kernel.resource.Resource;
import org.ldp4j.application.kernel.resource.ResourceId;
import org.ldp4j.application.kernel.resource.ResourceRepository;
import org.ldp4j.application.kernel.session.WriteSessionConfiguration;
import org.ldp4j.application.kernel.spi.RuntimeDelegate;
import org.ldp4j.application.kernel.template.ResourceTemplate;
import org.ldp4j.application.kernel.template.TemplateIntrospector;
import org.ldp4j.application.kernel.transaction.Transaction;
import org.ldp4j.application.kernel.transaction.TransactionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class DefaultApplicationContext implements ApplicationContext {

	private final class DefaultApplicationOperation implements ApplicationContextOperation {

		private final HttpRequest request;
		private final Transaction transaction;

		private DefaultApplicationOperation(HttpRequest request) {
			this.request = request;
			this.transaction=getContext().operationController.beginTransaction();
		}

		HttpRequest getRequest() {
			return this.request;
		}

		@Override
		public DefaultApplicationContext getContext() {
			return DefaultApplicationContext.this;
		}

		@Override
		public PublicResource findResource(String path) {
			return DefaultApplicationContext.this.findResource(path);
		}

		@Override
		public PublicResource resolveResource(String path) {
			return DefaultApplicationContext.this.resolveResource(path);
		}

		@Override
		public PublicResource resolveResource(ManagedIndividualId id) {
			return DefaultApplicationContext.this.resolveResource(id);
		}

		@Override
		public void dispose() {
			try {
				getContext().operationController.endTransaction(this.transaction);
			} finally {
				getContext().currentOperation.remove();
			}
		}

	}

	private final class ApplicationContextOperationController {

		private final TransactionManager transactionManager;

		private ApplicationContextOperationController() {
			this.transactionManager = RuntimeDelegate.getInstance().getTransactionManager();
		}

		public Transaction beginTransaction() {
			Transaction transaction = this.transactionManager.currentTransaction();
			transaction.begin();
			LOGGER.
				info("Started transaction {}.{},",
					Thread.currentThread().getName(),
					transaction);
			return transaction;
		}

		public void endTransaction(Transaction transaction) {
			if(transaction.isActive()) {
				transaction.rollback();
			}
			LOGGER.
				info("Completed transaction {}.{},",
					Thread.currentThread().getName(),
					transaction);
		}

	}

	private static final String APPLICATION_LIFECYCLE_LISTENER_CANNOT_BE_NULL = "Application lifecycle listener cannot be null";
	private static final String APPLICATION_INITILIZATION_FAILED              = "Application '{}' initilization failed";
	private static final String COULD_NOT_FIND_CONTAINER_FOR_ENDPOINT         = "Could not find container for endpoint '%s'";
	private static final String COULD_NOT_FIND_RESOURCE_FOR_ENDPOINT          = "Could not find resource for endpoint '%s'";
	private static final String RESOURCE_RETRIEVAL_FAILED                     = "Resource '%s' retrieval failed ";
	private static final String RESOURCE_QUERY_FAILED                         = "Resource '%s' query failed ";
	private static final String RESOURCE_CREATION_FAILED                      = "Resource creation failed at '%s'";
	private static final String RESOURCE_DELETION_FAILED                      = "Resource deletion failed at '%s'";
	private static final String RESOURCE_MODIFICATION_FAILED                  = "Resource modification failed at '%s'";

	private static final Logger LOGGER=LoggerFactory.getLogger(DefaultApplicationContext.class);

	private Application<Configuration> application;

	private Configuration configuration;

	private final DefaultPublicResourceFactory factory;

	private final DefaultApplicationEngine engine;

	private final ApplicationContextOperationController operationController;

	private final ThreadLocal<DefaultApplicationOperation> currentOperation;

	private final ResourceRepository resourceRepository;
	private final EndpointRepository endpointRepository;
	private final ConstraintReportRepository constraintReportRepository;

	DefaultApplicationContext(DefaultApplicationEngine engine) {
		this.engine=engine;
		this.resourceRepository=RuntimeDelegate.getInstance().getResourceRepository();
		this.endpointRepository=RuntimeDelegate.getInstance().getEndpointRepository();
		this.constraintReportRepository=RuntimeDelegate.getInstance().getConstraintReportRepository();
		this.factory=DefaultPublicResourceFactory.newInstance(this);
		this.operationController=new ApplicationContextOperationController();
		this.currentOperation=new ThreadLocal<DefaultApplicationOperation>();
	}

	private static <T> T checkNotNull(T object, String message) {
		if(object==null) {
			throw new ApplicationContextException(message);
		}
		return object;
	}

	private String applicationFailureMessage(String message, Object... objects) {
		return "[" + this.application.getName() + "] " + String.format(message,objects);
	}

	private Application<Configuration> application() {
		return this.application;
	}

	private ApplicationExecutionException createException(String errorMessage, Exception e) {
		LOGGER.error(errorMessage,e);
		if(e instanceof FeatureExecutionException) {
			return new ApplicationExecutionException(errorMessage,e.getCause());
		} else if(e instanceof FeaturePostconditionException) {
			return new ApplicationExecutionException(errorMessage,new ApplicationRuntimeException(e.getMessage()));
		}
		throw new ApplicationContextException(errorMessage,e);
	}

	private PublicResource findResource(final String path) {
		return resolveResource(path);
	}

	private PublicResource resolveResource(final String path) {
		checkNotNull(path,"Endpoint path cannot be null");
		Endpoint endpoint=
			engine().
				endpointManagementService().
					resolveEndpoint(path);
		return this.factory.createResource(endpoint);
	}

	private PublicResource resolveResource(ManagedIndividualId id) {
		checkNotNull(id,"Individual identifier cannot be null");
		return this.factory.createResource(resolveResource(ResourceId.createId(id.name(), id.managerId())));
	}

	private void processConstraintValidationFailure(Resource resource, Throwable failure) {
		if(failure.getCause() instanceof InvalidContentException) {
			InvalidContentException cause=(InvalidContentException)failure.getCause();
			registerConstraintReport(resource, cause);
		}
	}

	// TODO: How do we do this transactionally
	private void registerConstraintReport(Resource resource, InvalidContentException error) {
		ConstraintReport report=
			resource.
				addConstraintReport(
					error.getConstraints(),
					new Date(),
					currentRequest());
		this.constraintReportRepository.add(report);
		LOGGER.debug("Constraint validation failed. Registered constraint report {}",report.id());
		error.setConstraintsId(report.id().failureId());
	}

	private HttpRequest currentRequest() {
		DefaultApplicationOperation result = this.currentOperation.get();
		checkState(result!=null,"No in-flight operation");
		return result.getRequest();
	}

	/**
	 * Enforce http://tools.ietf.org/html/rfc7232#section-2.2:
	 * if the clock in the request is ahead of the clock of the origin
	 * server (e.g., I request from Spain the update of a resource held in USA)
	 * the last-modified data should be changed to that of the request and not
	 * a generated date from the origin server
	 */
	private Date lastModified() {
		Date clientDate = currentRequest().clientDate();
		Date lastModified=new Date();
		if(clientDate!=null && clientDate.after(lastModified)) {
			lastModified=clientDate;
		}
		return lastModified;
	}

	private Resource loadResource(ResourceId resourceId) {
		return this.resourceRepository.resourceById(resourceId,Resource.class);
	}

	DataSet getResource(Endpoint endpoint) throws ApplicationExecutionException {
		ResourceId resourceId=endpoint.resourceId();
		Resource resource = loadResource(resourceId);
		if(resource==null) {
			String errorMessage = applicationFailureMessage(COULD_NOT_FIND_RESOURCE_FOR_ENDPOINT,endpoint);
			LOGGER.error(errorMessage);
			throw new ApplicationExecutionException(errorMessage);
		}
		try {
			WriteSessionConfiguration config=
				DefaultApplicationContextHelper.
					create(this.engine().templateManagementService()).
						createConfiguration(resource,lastModified());
			return this.engine().resourceControllerService().getResource(resource,config);
		} catch (Exception e) {
			String errorMessage = applicationFailureMessage(RESOURCE_RETRIEVAL_FAILED,endpoint);
			throw createException(errorMessage,e);
		}
	}

	DataSet query(Endpoint endpoint, Query query) throws ApplicationExecutionException {
		ResourceId resourceId=endpoint.resourceId();
		Resource resource = loadResource(resourceId);
		if(resource==null) {
			String errorMessage = applicationFailureMessage(COULD_NOT_FIND_RESOURCE_FOR_ENDPOINT,endpoint);
			LOGGER.error(errorMessage);
			throw new ApplicationExecutionException(errorMessage);
		}
		try {
			WriteSessionConfiguration config=
				DefaultApplicationContextHelper.
					create(this.engine().templateManagementService()).
						createConfiguration(resource,lastModified());
			return this.engine().resourceControllerService().queryResource(resource,query,config);
		} catch (Exception e) {
			String errorMessage = applicationFailureMessage(RESOURCE_QUERY_FAILED,endpoint);
			throw createException(errorMessage,e);
		}
	}

	void registerContentFailure(Endpoint endpoint, InvalidContentException error) {
		registerConstraintReport(loadResource(endpoint.resourceId()),error);
	}

	Resource resolveResource(Endpoint endpoint) {
		return loadResource(endpoint.resourceId());
	}

	Endpoint resolveResource(ResourceId id) {
		return this.endpointRepository.endpointOfResource(id);
	}

	Resource createResource(Endpoint endpoint, DataSet dataSet, String desiredPath) throws ApplicationExecutionException {
		ResourceId resourceId=endpoint.resourceId();
		Container resource = this.resourceRepository.containerOfId(resourceId);
		if(resource==null) {
			String errorMessage = applicationFailureMessage(COULD_NOT_FIND_CONTAINER_FOR_ENDPOINT,endpoint);
			LOGGER.error(errorMessage);
			throw new ApplicationExecutionException(errorMessage);
		}
		try {
			WriteSessionConfiguration config=
				DefaultApplicationContextHelper.
					create(this.engine().templateManagementService()).
						createConfiguration(resource,dataSet,desiredPath,lastModified());
			return this.engine().resourceControllerService().createResource(resource,dataSet,config);
		} catch (FeatureExecutionException e) {
			processConstraintValidationFailure(resource, e);
			String errorMessage = applicationFailureMessage(RESOURCE_CREATION_FAILED,endpoint);
			throw createException(errorMessage,e);
		} catch (InvalidIndirectIdentifierException e) {
			// Just rethrow
			throw e;
		} catch (Exception e) {
			String errorMessage = applicationFailureMessage(RESOURCE_CREATION_FAILED,endpoint);
			throw createException(errorMessage,e);
		}
	}

	void deleteResource(Endpoint endpoint) throws ApplicationExecutionException {
		ResourceId resourceId=endpoint.resourceId();
		Resource resource = loadResource(resourceId);
		if(resource==null) {
			String errorMessage = applicationFailureMessage(COULD_NOT_FIND_CONTAINER_FOR_ENDPOINT,endpoint);
			LOGGER.error(errorMessage);
			throw new ApplicationExecutionException(errorMessage);
		}
		try {
			WriteSessionConfiguration config=
				DefaultApplicationContextHelper.
					create(this.engine().templateManagementService()).
						createConfiguration(resource,lastModified());
			this.engine().resourceControllerService().deleteResource(resource,config);
		} catch (Exception e) {
			String errorMessage = applicationFailureMessage(RESOURCE_DELETION_FAILED,endpoint);
			throw createException(errorMessage,e);
		}
	}

	void modifyResource(Endpoint endpoint, DataSet dataSet) throws ApplicationExecutionException {
		ResourceId resourceId=endpoint.resourceId();
		Resource resource = loadResource(resourceId);
		if(resource==null) {
			String errorMessage = applicationFailureMessage(COULD_NOT_FIND_RESOURCE_FOR_ENDPOINT,endpoint);
			LOGGER.error(errorMessage);
			throw new ApplicationExecutionException(errorMessage);
		}
		try {
			WriteSessionConfiguration config=
				DefaultApplicationContextHelper.
					create(this.engine().templateManagementService()).
						createConfiguration(resource,lastModified());
			this.engine().resourceControllerService().updateResource(resource,dataSet,config);
		} catch (FeatureExecutionException e) {
			processConstraintValidationFailure(resource, e);
			String errorMessage = applicationFailureMessage(RESOURCE_MODIFICATION_FAILED,endpoint);
			throw createException(errorMessage,e);
		} catch (Exception e) {
			String errorMessage = applicationFailureMessage(RESOURCE_MODIFICATION_FAILED,endpoint);
			throw createException(errorMessage,e);
		}
	}

	DataSet getConstraintReport(Endpoint endpoint, String constraintsId) throws ApplicationExecutionException {
		ResourceId resourceId=endpoint.resourceId();
		// TODO: Check if it is really necessary
		Resource resource = loadResource(resourceId);
		if(resource==null) {
			String errorMessage = applicationFailureMessage(COULD_NOT_FIND_RESOURCE_FOR_ENDPOINT,endpoint);
			LOGGER.error(errorMessage);
			throw new ApplicationExecutionException(errorMessage);
		}

		ConstraintReport report=
			this.constraintReportRepository.
				constraintReportOfId(
					ConstraintReportId.
						create(resource.id(),constraintsId));
		if(report==null) {
			return null;
		}

		return
			ConstraintReportTransformer.
				create(resource, report).
					transform(endpoint);
	}

	Capabilities endpointCapabilities(Endpoint endpoint) {
		MutableCapabilities result=new MutableCapabilities();
		Resource resource = resolveResource(endpoint);
		ResourceTemplate template=resourceTemplate(resource);
		Class<? extends ResourceHandler> handlerClass = template.handlerClass();
		result.setQueryable(Queryable.class.isAssignableFrom(handlerClass));
		result.setModifiable(Modifiable.class.isAssignableFrom(handlerClass));
		result.setDeletable(Deletable.class.isAssignableFrom(handlerClass) && !resource.isRoot());
		// TODO: Analyze how to provide patch support
		result.setPatchable(false);
		TemplateIntrospector introspector = TemplateIntrospector.newInstance(template);
		result.setFactory(introspector.isContainer());
		return result;
	}

	ResourceTemplate resourceTemplate(Resource resource) {
		return this.engine().templateManagementService().templateOfId(resource.id().templateId());
	}

	void initialize(String applicationClassName) throws ApplicationContextCreationException {
		try {
			this.application=this.engine().applicationLifecycleService().initialize(applicationClassName);
			this.configuration=this.engine().applicationLifecycleService().configuration();
		} catch (ApplicationContextCreationException e) {
			LOGGER.error(APPLICATION_INITILIZATION_FAILED,applicationClassName,e);
			throw e;
		}
	}

	boolean shutdown() {
		return true;
	}

	DefaultApplicationEngine engine() {
		return this.engine;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String applicationName() {
		return application().getName();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String applicationClassName() {
		return this.application.getClass().getName();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Namespaces applicationNamespaces() {
		return this.configuration.namespaces();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ApplicationContextOperation createOperation(HttpRequest request) {
		checkNotNull(request,"Http request cannot be null");
		DefaultApplicationOperation operation=this.currentOperation.get();
		checkState(operation==null,"An operation is ongoing on the current thread");
		operation=new DefaultApplicationOperation(request);
		this.currentOperation.set(operation);
		return operation;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void registerApplicationLifecycleListener(ApplicationLifecycleListener listener) {
		checkNotNull(listener,APPLICATION_LIFECYCLE_LISTENER_CANNOT_BE_NULL);
		this.engine().applicationLifecycleService().registerApplicationLifecycleListener(listener);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void deregisterApplicationLifecycleListener(ApplicationLifecycleListener listener) {
		checkNotNull(listener,APPLICATION_LIFECYCLE_LISTENER_CANNOT_BE_NULL);
		this.engine().applicationLifecycleService().deregisterApplicationLifecycleListener(listener);
	}

}


/**
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   This file is part of the LDP4j Project:
 *     http://www.ldp4j.org/
 *
 *   Center for Open Middleware
 *     http://www.centeropenmiddleware.com/
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Copyright (C) 2014-2016 Center for Open Middleware.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   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.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Artifact    : org.ldp4j.framework:ldp4j-application-engine-sdk:0.2.2
 *   Bundle      : ldp4j-application-engine-sdk-0.2.2.jar
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 */
package org.ldp4j.application.sdk.internal;

import org.ldp4j.application.sdk.spi.ObjectFactory;
import org.ldp4j.application.sdk.spi.ObjectParseException;

/**
 * Object factory for parsing and formating enum types relying on the standard
 * Enum class facilities for parsing and formatting
 */
public final class EnumObjectFactory<E extends Enum<E>> implements ObjectFactory<E> {

	private final Class<E> targetClass;

	private EnumObjectFactory(Class<E> targetClass) {
		this.targetClass = targetClass;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Class<? extends E> targetClass() {
		return this.targetClass;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public E fromString(final String rawValue) {
		try {
			return Enum.valueOf(this.targetClass, rawValue);
		} catch (Exception e) {
			throw new ObjectParseException(e,targetClass(),rawValue);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String toString(E value) {
		return value.toString();
	}

	public static <S extends Enum<S>> ObjectFactory<S> create(Class<S> enumClass) {
		return new EnumObjectFactory<S>(enumClass);
	}

}


/**
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   This file is part of the LDP4j Project:
 *     http://www.ldp4j.org/
 *
 *   Center for Open Middleware
 *     http://www.centeropenmiddleware.com/
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Copyright (C) 2014-2016 Center for Open Middleware.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   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.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Artifact    : org.ldp4j.framework:ldp4j-application-examples:0.2.2
 *   Bundle      : ldp4j-application-examples-0.2.2.jar
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 */
package org.ldp4j.example;

import java.net.URI;

import org.ldp4j.application.data.DataSet;
import org.ldp4j.application.data.ManagedIndividual;
import org.ldp4j.application.data.ManagedIndividualId;
import org.ldp4j.application.data.Property;
import org.ldp4j.application.data.constraints.Constraints;
import org.ldp4j.application.data.validation.ValidationConstraint;
import org.ldp4j.application.data.validation.ValidationConstraintFactory;
import org.ldp4j.application.data.validation.ValidationReport;
import org.ldp4j.application.data.validation.Validator;
import org.ldp4j.application.ext.ApplicationRuntimeException;
import org.ldp4j.application.ext.Deletable;
import org.ldp4j.application.ext.InconsistentContentException;
import org.ldp4j.application.ext.Modifiable;
import org.ldp4j.application.ext.UnknownResourceException;
import org.ldp4j.application.ext.annotations.Attachment;
import org.ldp4j.application.ext.annotations.Resource;
import org.ldp4j.application.session.ResourceSnapshot;
import org.ldp4j.application.session.WriteSession;
import org.ldp4j.application.session.WriteSessionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Example resource handler with multiple attachments.
 */
@Resource(
	id=PersonHandler.ID,
	attachments={
		@Attachment(
			id=PersonHandler.ADDRESS_ID,
			path=PersonHandler.ADDRESS_PATH,
			predicate="http://www.ldp4j.org/vocabularies/example#address",
			handler=AddressHandler.class),
		@Attachment(
			id="books",
			path="books",
			handler=BookContainerHandler.class),
		@Attachment(
			id=PersonHandler.RELATIVES_ID,
			path=PersonHandler.RELATIVES_PATH,
			handler=RelativeContainerHandler.class)
	}
)
public class PersonHandler extends InMemoryResourceHandler implements Modifiable, Deletable {

	private static final Logger LOGGER=LoggerFactory.getLogger(PersonHandler.class);

	/**
	 * The identifier of the template defined by the handler.
	 */
	public static final String ID="personTemplate";

	/**
	 * The identifier of the relative attachment of the template defined by the handler.
	 */
	public static final String RELATIVES_ID   = "personRelatives";

	/**
	 * The path of the relative attachment of the template defined by the handler.
	 */
	public static final String RELATIVES_PATH = "relatives";

	/**
	 * The identifier of the address attachment of the template defined by the handler.
	 */
	public static final String ADDRESS_ID="address";

	/**
	 * The path of the address attachment of the template defined by the handler.
	 */
	public static final String ADDRESS_PATH="address";

	/**
	 * Read-only-property validate by the business logic.
	 */
	public static final URI READ_ONLY_PROPERTY = URI.create("http://www.example.org/vocab#creationDate");

	/**
	 * Create a new instance.
	 */
	public PersonHandler() {
		super("Person");
	}

	/**
	 * {@inheritDoc}

	 *
	 * Delete a person resource.
	 */
	@Override
	public void delete(ResourceSnapshot resource, WriteSession session) throws UnknownResourceException {
		DataSet dataSet = get(resource);
		try {
			logDebug(resource,"Deleting state:%n%s",dataSet);
			remove(resource.name());
			session.delete(resource);
			session.saveChanges();
		} catch (WriteSessionException e) {
			// Recover if failed
			add(resource.name(),dataSet);
			throw new ApplicationRuntimeException("Deletion failed",e);
		}
	}

	/**
	 * {@inheritDoc}

	 *
	 * Update a person resource.
	 */
	@Override
	public void update(ResourceSnapshot resource, DataSet content, WriteSession session) throws InconsistentContentException, UnknownResourceException {
		DataSet dataSet = get(resource);
		logDebug(resource, "Enforcing consistency...");
		enforceConsistency(resource,content,dataSet);
		try {
			logDebug(resource,"Persisting new state:%n%s",content);
			add(resource.name(),content);
			session.modify(resource);
			session.saveChanges();
		} catch (Exception e) {
			// Recover if failed
			add(resource.name(),dataSet);
			logError(resource,e,"Something went wrong",e);
			throw new ApplicationRuntimeException("Update failed",e);
		}
	}

	protected void logDebug(ResourceSnapshot resource, String message, Object... args) {
		LOGGER.debug("[{}] {}",resource.name(),String.format(message,args));
	}

	protected void logError(ResourceSnapshot resource, Throwable t, String message, Object... args) {
		LOGGER.error("[{}] {}",resource.name(),String.format(message,args),t);
	}

	protected void enforceConsistency(ResourceSnapshot resource, DataSet content, DataSet dataSet) throws InconsistentContentException {
		ManagedIndividualId id = ManagedIndividualId.createId(resource.name(),PersonHandler.ID);
		ManagedIndividual stateIndividual =
			dataSet.
				individual(
					id,
					ManagedIndividual.class);
		Property stateProperty=
				stateIndividual.property(PersonHandler.READ_ONLY_PROPERTY);

		ValidationConstraint<Property> constraint=null;
		if(stateProperty!=null) {
			constraint=ValidationConstraintFactory.readOnlyProperty(stateProperty);
		} else {
			constraint=ValidationConstraintFactory.readOnlyProperty(id,PersonHandler.READ_ONLY_PROPERTY);
		}

		Validator helper =
			Validator.
				builder().
					withPropertyConstraint(constraint).
					build();

		ValidationReport report = helper.validate(content);
		if(!report.isValid()) {
			InconsistentContentException error = new InconsistentContentException("Validation failed: "+report.validationFailures(), Constraints.constraints());
			logError(resource,error,"Something went wrong when validating %n%s",content);
			throw error;
		}
	}

}


/**
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   This file is part of the LDP4j Project:
 *     http://www.ldp4j.org/
 *
 *   Center for Open Middleware
 *     http://www.centeropenmiddleware.com/
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Copyright (C) 2014-2016 Center for Open Middleware.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   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.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Artifact    : org.ldp4j.framework:ldp4j-application-examples:0.2.2
 *   Bundle      : ldp4j-application-examples-0.2.2.jar
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 */
package org.ldp4j.example;

import static org.ldp4j.application.data.IndividualReferenceBuilder.newReference;

import java.util.Date;

import org.ldp4j.application.data.DataDSL;
import org.ldp4j.application.data.DataSet;
import org.ldp4j.application.ext.annotations.Resource;

/**
 * An example resource handler whose resource representations include data that
 * cannot be resolved.
 */
@Resource(
	id=BadDataResourceHandler.ID
)
public class BadDataResourceHandler extends InMemoryResourceHandler {

	private static final String HAS_FATHER = "http://www.ldp4j.org/vocabulary/example#hasFather";

	private static final String AGE = "http://www.ldp4j.org/vocabulary/example#age";

	private static final String CREATION_DATE = "http://www.ldp4j.org/vocabulary/example#creationDate";

	private static final String KNOWS = "http://www.ldp4j.org/vocabulary/example#knows";

	/**
	 * A property that will be serialized for a blank node linked to an unknown
	 * managed individual.
	 */
	public static final String CREATED_ON = "http://www.ldp4j.org/vocabulary/example#createdOn";

	/**
	 * A property that will be serialized for a blank node that is linked from
	 * an unknown individual.
	 */
	public static final String HAS_WIFE = "http://www.ldp4j.org/vocabulary/example#hasWife";

	/**
	 * The identifier of the template defined by the handler.
	 */
	public static final String ID="BadDataResourceHandler";

	/**
	 * Create a new instance.
	 */
	public BadDataResourceHandler() {
		super(ID);
	}

	/**
	 * Get custom representation with bad data
	 *
	 * @return the representation
	 */
	public DataSet getRepresentation() {
		return
			DataDSL.
				dataSet().
					individual(newReference().toLocalIndividual().named("anonymous")).
						hasLink(KNOWS).
							referringTo(newReference().toManagedIndividual("unknownTemplate1").named("r1")).
					individual(newReference().toLocalIndividual().named("anonymous")).
						hasProperty(CREATED_ON).
							withValue(new Date()).
						hasLink(KNOWS).
							referringTo(newReference().toManagedIndividual("unknownTemplate2").named("r1")).
					individual(newReference().toManagedIndividual("unknownTemplate2").named("r1")).
						hasProperty(CREATION_DATE).
							withValue(new Date()).
						hasProperty(AGE).
							withValue(34).
						hasLink(HAS_FATHER).
							toIndividual(newReference().toLocalIndividual().named("Michel")).
								hasLink(HAS_WIFE).
									referringTo(newReference().toLocalIndividual().named("Consuelo")).
					build();
	}

	/**
	 * Get all the properties that will be filtered.
	 *
	 * @return the properties to be filtered
	 */
	public static final String[] filteredProperties() {
		return new String[]{
			HAS_FATHER,
			AGE,
			CREATION_DATE,
			KNOWS
		};
	}

}