CVE-2016-15018 (Java, published 2023-01-15T19:15Z)
Description: value: A vulnerability was found in krail-jpa up to 0.9.1. It has been classified as critical. This affects an unknown part. The manipulation leads to sql injection. Upgrading to version 0.9.2 is able to address this issue. The identifier of the patch is c1e848665492e21ef6cc9be443205e36b9a1f6be. It is recommended to upgrade the affected component. The identifier VDB-218373 was assigned to this vulnerability.
Severity: nan (CVSS v3 base score: 9.8)
Weakness: CWE-89 \u2014 Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data.
Repository: https://github.com/KrailOrg/krail-jpa
Files changed:
src/main/java/uk/q3c/krail/jpa/i18n/DefaultJpaPatternDao.java
src/main/java/uk/q3c/krail/jpa/i18n/JpaPatternDao.java
src/main/java/uk/q3c/krail/jpa/i18n/JpaPatternEntity.java
src/main/java/uk/q3c/krail/jpa/i18n/KeyValueEntity.java
src/main/java/uk/q3c/krail/jpa/i18n/PatternId.java
src/main/java/uk/q3c/krail/jpa/persist/BaseJpaDao.java
src/main/java/uk/q3c/krail/jpa/persist/BaseJpaKeyValueDao.java
src/main/java/uk/q3c/krail/jpa/persist/DefaultJpaInstanceConfiguration.java
src/main/java/uk/q3c/krail/jpa/persist/JpaKeyValueDao.java
src/main/java/uk/q3c/krail/jpa/user/opt/DefaultJpaOptionContainerProvider.java
src/main/java/uk/q3c/krail/jpa/user/opt/DefaultJpaOptionDao.java
src/main/java/uk/q3c/krail/jpa/user/opt/JpaOptionDao.java
src/main/java/uk/q3c/krail/jpa/user/opt/JpaOptionEntity.java
src/main/java/uk/q3c/krail/jpa/user/opt/OptionId.java
src/test/java/uk/q3c/krail/jpa/i18n/DefaultJpaPatternDao__IntegrationTest.groovy
src/test/java/uk/q3c/krail/jpa/i18n/JpaPatternEntity_Test.groovy
src/test/java/uk/q3c/krail/jpa/persist/TestJpaModule.java
src/test/java/uk/q3c/krail/jpa/user/opt/DefaultJpaOptionDaoTest.groovy
src/test/java/uk/q3c/krail/jpa/user/opt/DefaultJpaOptionDao__DataTypeTest.groovy
src/test/java/uk/q3c/krail/jpa/user/opt/DefaultJpaOptionDao__IntegrationTest.groovy
src/test/java/uk/q3c/krail/jpa/user/opt/DefaultOptionJpaDaoTest2.java
src/test/resources/META-INF/persistence.xml
Commit message: Fix #18 SQLInjection vulnerability cleared

Pattern and Option DAOs re-written to a common key-value base class.  Using composite primary key in place of surrogate key.


Vulnerable code:
/*
 * Copyright (c) 2015. David Sowerby
 *
 * 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 uk.q3c.krail.jpa.i18n;

import com.google.inject.Inject;
import org.apache.onami.persist.EntityManagerProvider;
import org.apache.onami.persist.PersistenceUnitModule;
import org.apache.onami.persist.Transactional;
import uk.q3c.krail.core.data.Select;
import uk.q3c.krail.i18n.PatternCacheKey;
import uk.q3c.krail.jpa.persist.DefaultJpaDao_LongInt;

import javax.annotation.Nonnull;
import javax.persistence.TypedQuery;
import java.util.List;
import java.util.Optional;

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

/**
 * The default implementation of {@link JpaPatternDao}.  The {@code entityManagerProvider} and {@code dao} are bound by {@link PersistenceUnitModule} to the
 * annotation which is used in the injection of this class. (For example, if an instance of this class is annotated with @Jpa1, then the constructor parameters
 * will also be bound with @Jpa1)
 * <p>
 * Created by David Sowerby on 15/04/15.
 */
public class DefaultJpaPatternDao_LongInt extends DefaultJpaDao_LongInt implements JpaPatternDao {

    @Inject
    protected DefaultJpaPatternDao_LongInt(EntityManagerProvider entityManagerProvider) {
        super(entityManagerProvider);
    }

    @Transactional
    @Override
    public void write(@Nonnull PatternCacheKey cacheKey, @Nonnull String value) {
        checkNotNull(cacheKey);
        checkNotNull(value);
        Optional<PatternEntity_LongInt> existingValue = find(cacheKey);
        if (existingValue.isPresent()) {
            existingValue.get()
                         .setValue(value);
            save(existingValue.get());
        } else {
            save(keyToEntity(cacheKey, value));
        }
    }

    @Nonnull
    protected PatternEntity_LongInt keyToEntity(@Nonnull PatternCacheKey key, @Nonnull String value) {
        return new PatternEntity_LongInt(key, value);
    }

    @Transactional
    @Override
    @Nonnull
    public Optional<PatternEntity_LongInt> find(@Nonnull PatternCacheKey cacheKey) {
        checkNotNull(cacheKey);
        Select select = selectEntity(cacheKey);

        TypedQuery<PatternEntity_LongInt> query = getEntityManager().createQuery(select.toString(), PatternEntity_LongInt.class);
        List<PatternEntity_LongInt> results = query.getResultList();
        if (results.isEmpty()) {
            return Optional.empty();
        } else {
            return Optional.of(results.get(0));
        }
    }

    protected Select selectEntity(PatternCacheKey cacheKey) {
        //ensure the same conversion as writing
        PatternEntity_LongInt searchKey = new PatternEntity_LongInt(cacheKey, "x");
        return new Select().from(entityName(PatternEntity_LongInt.class))
                           .where("i18nkey", searchKey.getI18nkey())
                           .and("locale", searchKey.getLocale());
    }

    @Transactional
    @Nonnull
    @Override
    public Optional<String> deleteValue(@Nonnull PatternCacheKey cacheKey) {
        checkNotNull(cacheKey);


        TypedQuery<PatternEntity_LongInt> query = getEntityManager().createQuery(selectFromKey(cacheKey), PatternEntity_LongInt.class);
        List<PatternEntity_LongInt> results = query.getResultList();
        if (results.isEmpty()) {
            return Optional.empty();
        } else {
            final Optional<PatternEntity_LongInt> patternEntity = deleteById(PatternEntity_LongInt.class, results.get(0)
                                                                                                 .getId());
            if (patternEntity.isPresent()) {
                return Optional.of(patternEntity.get()
                                                .getValue());
            } else {
                return Optional.empty();
            }
        }
    }

    /**
     * Returns a Select String from the {@code cacheKey}.  Uses {@link PatternEntity_LongInt} to ensure conversion from key to entity is consistent for the esearch
     * compared to the original write
     *
     * @param cacheKey
     *         the key being selected
     *
     * @return a Select String from the {@code cacheKey}
     */
    protected String selectFromKey(@Nonnull PatternCacheKey cacheKey) {
        PatternEntity_LongInt searchPattern = keyToEntity(cacheKey, "x");
        return new Select().from(PatternEntity_LongInt.class)
                           .where("i18nkey", searchPattern.getI18nkey())
                           .and("locale", searchPattern.getLocale())
                           .toString();
    }

    @Nonnull
    @Override
    public Optional<String> getValue(@Nonnull PatternCacheKey cacheKey) {
        checkNotNull(cacheKey);
        Optional<PatternEntity_LongInt> entity = find(cacheKey);
        if (entity.isPresent()) {
            return Optional.of(entity.get()
                                     .getValue());
        } else {
            return Optional.empty();
        }
    }

    /**
     * returns the number of entries
     *
     * @return the number of entries
     */
    @Override
    @Transactional
    public long count() {
        return super.count(PatternEntity_LongInt.class);
    }


}
 * Copyright (c) 2015. David Sowerby
 * 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.
import java.util.Optional;

    Optional<PatternEntity_LongInt> find(PatternCacheKey cacheKey);
/*
 * Copyright (c) 2015. David Sowerby
 *
 * 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 uk.q3c.krail.jpa.i18n;

import uk.q3c.krail.core.data.EnumConverter;
import uk.q3c.krail.i18n.PatternCacheKey;
import uk.q3c.krail.jpa.persist.EntityBase_LongInt;

import javax.persistence.Entity;

/**
 * An entity to represent an I18N key, Locale and value combination
 * <p>
 * Created by David Sowerby on 15/04/15.
 */

@Entity
public class PatternEntity_LongInt extends EntityBase_LongInt {

    private String i18nkey;
    private String locale;
    private String value;

    public PatternEntity_LongInt() {
    }

    public PatternEntity_LongInt(PatternCacheKey cacheKey, String value) {
        final Enum<?> enumKey = cacheKey.getKey();
        this.i18nkey = new EnumConverter().convertToString(enumKey);
        this.locale = cacheKey.getRequestedLocale()
                              .toLanguageTag();
        this.value = value;
    }

    public String getI18nkey() {
        return i18nkey;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getLocale() {
        return locale;
    }
}
 * Copyright (c) 2015. David Sowerby
 * 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.
    public <E extends KrailEntity<ID, VER>> String entityName(@Nonnull Class<E> entityClass) {
     * {@inheritDoc}
import uk.q3c.krail.jpa.i18n.DefaultJpaPatternDao_LongInt;
import uk.q3c.krail.jpa.user.opt.DefaultOptionJpaDao_LongInt;
        bind(OptionDao.class, DefaultOptionJpaDao_LongInt.class);
        bind(PatternDao.class, DefaultJpaPatternDao_LongInt.class);
 * Copyright (c) 2015. David Sowerby
 * 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.
        return jpaContainerProvider.get(OptionEntity_LongInt.class, containerType);
import com.google.common.base.Preconditions;
import uk.q3c.krail.core.user.opt.OptionException;
import uk.q3c.krail.jpa.persist.DefaultJpaDao_LongInt;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
 * Converts {@link OptionCacheKey} to {@link OptionEntity_LongInt} for persistence.
public class DefaultOptionJpaDao_LongInt extends DefaultJpaDao_LongInt implements OptionJpaDao_LongInt {
    protected DefaultOptionJpaDao_LongInt(EntityManagerProvider entityManagerProvider, OptionStringConverter optionStringConverter) {
        super(entityManagerProvider);
    @Override
    @Transactional
    @Nonnull
    public <V> Object write(@Nonnull OptionCacheKey cacheKey, @Nonnull Optional<V> value) {
        checkRankOption(cacheKey, SPECIFIC_RANK);
        Preconditions.checkArgument(value.isPresent(), "Value must be non-empty");
        EntityManager entityManager = getEntityManager();
        // is there an existing entity (bearing in mind that the id field is not the same as the key field
        String stringValue = optionStringConverter.convertValueToString(value.get());
        Optional<OptionEntity_LongInt> existingEntity = find(cacheKey);
        if (existingEntity.isPresent()) {
            OptionEntity_LongInt existing = existingEntity.get();
            existing
                          .setValue(stringValue);
            entityManager.persist(existingEntity.get());
            return existing;
        } else {
            //noinspection ConstantConditions
            final OptionEntity_LongInt entity = new OptionEntity_LongInt(cacheKey, stringValue);
            entityManager.persist(entity);
            return entity;
        }

    }

    @Transactional
    @Nonnull
    public Optional<OptionEntity_LongInt> find(@Nonnull OptionCacheKey cacheKey) {
        checkRankOption(cacheKey, SPECIFIC_RANK);

        Select select = selectSingleRank(cacheKey);

        TypedQuery<OptionEntity_LongInt> query = getEntityManager().createQuery(select.statement(), OptionEntity_LongInt.class);
        List<OptionEntity_LongInt> results = query.getResultList();
        if (results.isEmpty()) {
            return Optional.empty();
        } else {
            if (results.size() > 1) {
                throw new OptionException("Multiple values for one cache key found, cacheKey =  " + cacheKey);
            }
            return Optional.of(results.get(0));
        }
    }

        return new Select().from(entityName(OptionEntity_LongInt.class))
    @Transactional
    @Nonnull
    @Override
    public Optional<?> deleteValue(@Nonnull OptionCacheKey cacheKey) {
        checkRankOption(cacheKey, SPECIFIC_RANK);
        final Optional<OptionEntity_LongInt> entity = find(cacheKey);
        if (entity.isPresent()) {
            String entityValue = entity.get()
                                       .getValue();
            delete(entity.get());
            return Optional.of(entityValue);
        } else {
            return Optional.empty();
        }
    }

        final Optional<OptionEntity_LongInt> optionalEntity = find(cacheKey);
        if (optionalEntity.isPresent()) {

            String value = optionalEntity.get()
                                         .getValue();

            return Optional.of(optionStringConverter.convertStringToValue(cacheKey, value));
        } else {
            return Optional.empty();
        }
        final Query query = getEntityManager().createQuery("DELETE FROM " + entityName(OptionEntity_LongInt.class));
        return query.executeUpdate();
        return super.count(OptionEntity_LongInt.class);
/*
 * Copyright (c) 2015. David Sowerby
 *
 * 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 uk.q3c.krail.jpa.user.opt;

import uk.q3c.krail.core.user.opt.Option;
import uk.q3c.krail.core.user.opt.cache.OptionCacheKey;
import uk.q3c.krail.jpa.persist.EntityBase_LongInt;

import javax.annotation.Nonnull;
import javax.persistence.Entity;

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

/**
 * An entity to hold data for an {@link Option}.  The value is held as a String to enable the use of a single column for it.  Context is part of the overall
 * {#optionKey} to ensure uniqueness, but is also held separately as it is a useful way to group the options for manual setting up, and there may also be an
 * opportunity to pre-load options by Context.
 * <p>
 * Created by David Sowerby on 13/04/15.
 */
@Entity
public class OptionEntity_LongInt extends EntityBase_LongInt {

    private String context;
    private String optionKey;
    private String rankName;
    private String userHierarchyName;
    private String value;

    public OptionEntity_LongInt() {
    }

    public OptionEntity_LongInt(@Nonnull OptionCacheKey optionCacheKey, @Nonnull String value) {
        userHierarchyName = optionCacheKey.getHierarchy()
                                          .persistenceName();
        rankName = optionCacheKey.getRequestedRankName();
        optionKey = optionCacheKey.getOptionKey()
                                  .compositeKey();
        context = optionCacheKey.getOptionKey()
                                .getContext()
                                .getName();
        this.value = value;

    }

    public String getContext() {
        return context;
    }

    public String getUserHierarchyName() {
        return userHierarchyName;
    }

    public void setUserHierarchyName(String userHierarchyName) {
        this.userHierarchyName = userHierarchyName;
    }

    public String getRankName() {
        return rankName;
    }

    public void setRankName(String rankName) {
        this.rankName = rankName;
    }

    public String getOptionKey() {
        return optionKey;
    }

    public void setOptionKey(String optionKey) {
        this.optionKey = optionKey;
    }

    @Nonnull
    public String getValue() {
        return value;
    }

    public void setValue(@Nonnull String value) {
        checkNotNull(value);
        this.value = value;
    }


}
/*
 * Copyright (c) 2015. David Sowerby
 *
 * 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 uk.q3c.krail.jpa.user.opt;

import uk.q3c.krail.core.user.opt.OptionDao;

/**
 * Created by David Sowerby on 13/04/15.
 */
public interface OptionJpaDao_LongInt extends OptionDao {

}
 * Copyright (c) 2015. David Sowerby
 * 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.

class DefaultJpaPatternDao_LongInt_IntegrationTest extends Specification {
        persistenceService.isRunning() == true
        unitOfWork.isActive() == true
        Optional<PatternEntity_LongInt> actual = (Optional<PatternEntity_LongInt>) dao.find(cacheKey)
        actual.isPresent()
        actual.get().getValue() == "4"
        Optional<PatternEntity_LongInt> actual = (Optional<PatternEntity_LongInt>) dao.find(cacheKey)
        actual.isPresent()
        actual.isPresent()
        actual.get().getValue() == "6"
        Optional<PatternEntity_LongInt> result2 = dao.find(cacheKey2)
        Optional<PatternEntity_LongInt> result3 = dao.find(cacheKey3)
        result2.get().getValue() == "4"
        result3.get().getValue() == "5"
/*
 * Copyright (c) 2015. David Sowerby
 *
 * 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 uk.q3c.krail.jpa.i18n

import spock.lang.Specification
import uk.q3c.krail.i18n.LabelKey
import uk.q3c.krail.i18n.PatternCacheKey

/**
 * Created by David Sowerby on 13/07/15.
 */
class PatternEntity_LongIntTest extends Specification {


    PatternEntity_LongInt entity;

    def "create decodes the I18NKey"() {
        given:

        PatternCacheKey cacheKey1 = new PatternCacheKey(LabelKey.Yes, Locale.UK)

        when:

        entity = new PatternEntity_LongInt(cacheKey1, "x")


        then:

        entity.getI18nkey().equals("uk.q3c.krail.i18n.LabelKey.Yes")
    }
}
 * Copyright (c) 2015. David Sowerby
 * 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.
import uk.q3c.krail.jpa.i18n.DefaultJpaPatternDao_LongInt;
import uk.q3c.krail.jpa.user.opt.DefaultOptionJpaDao_LongInt;
import uk.q3c.krail.jpa.user.opt.OptionJpaDao_LongInt;
                      bind(OptionJpaDao_LongInt.class, DefaultOptionJpaDao_LongInt.class)
              .bind(JpaPatternDao.class, DefaultJpaPatternDao_LongInt.class);
 * Copyright (c) 2015. David Sowerby
 * 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.
 * Test for {@link uk.q3c.krail.jpa.user.opt.DefaultOptionJpaDao_LongInt}
class DefaultOptionJpaDao_LongIntTest extends Specification {
    TypedQuery<OptionEntity_LongInt> query = Mock()
    List<OptionEntity_LongInt> emptyResultList;
    DefaultOptionJpaDao_LongInt dao
        dao = new DefaultOptionJpaDao_LongInt(entityManagerProvider, stringPersistenceConverter)
        entity instanceof OptionEntity_LongInt
        OptionEntity_LongInt rEntity = (OptionEntity_LongInt) entity
        List<OptionEntity_LongInt> resultList = new ArrayList<>();
        resultList.add((OptionEntity_LongInt) entity)
        entity instanceof OptionEntity_LongInt
        OptionEntity_LongInt rEntity = (OptionEntity_LongInt) entity
 * Copyright (c) 2015. David Sowerby
 * 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.
class DefaultOptionJpaDao_LongInt_DataTypeTest extends Specification {
 * Copyright (c) 2015. David Sowerby
 * 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.
class DefaultOptionJpaDao_LongInt_IntegrationTest extends Specification {
        OptionEntity_LongInt actual = (OptionEntity_LongInt) dao.write(cacheKey, Optional.of("4"));
        OptionEntity_LongInt actual = (OptionEntity_LongInt) dao.write(cacheKey, Optional.of("4"));
        actual = (OptionEntity_LongInt) dao.write(cacheKey, Optional.of("5"));
        actual = (OptionEntity_LongInt) dao.write(cacheKey, Optional.of("6"));
        Optional<OptionEntity_LongInt> result = dao.find(cacheKey)
        result.isPresent()
        result.get().getValue() == "6"
        Optional<OptionEntity_LongInt> result1 = dao.find(cacheKey1)
        Optional<OptionEntity_LongInt> result2 = dao.find(cacheKey2)
        result1.get().getValue() == "4"
        result2.get().getValue() == "5"
 * Copyright (c) 2015. David Sowerby
 * 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.
public class DefaultOptionJpaDaoLongIntTest extends JpaDaoTestBase {
    OptionJpaDao_LongInt dao;
        final Key<OptionJpaDao_LongInt> daoKey = Key.get(OptionJpaDao_LongInt.class, Jpa1.class);
  ~ Copyright (c) 2015. David Sowerby
  ~
  ~ 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.
        <class>uk.q3c.krail.jpa.user.opt.OptionEntity_LongInt</class>
        <class>uk.q3c.krail.jpa.i18n.PatternEntity_LongInt</class>
        <class>uk.q3c.krail.jpa.user.opt.OptionEntity_LongInt</class>
        <class>uk.q3c.krail.jpa.i18n.PatternEntity_LongInt</class>
        <class>uk.q3c.krail.jpa.user.opt.OptionEntity_LongInt</class>
        <class>uk.q3c.krail.jpa.i18n.PatternEntity_LongInt</class>
        <class>uk.q3c.krail.jpa.user.opt.OptionEntity_LongInt</class>
        <class>uk.q3c.krail.jpa.i18n.PatternEntity_LongInt</class>

Fixed code:
/*
 *
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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 uk.q3c.krail.jpa.i18n;

import com.google.inject.Inject;
import org.apache.onami.persist.EntityManagerProvider;
import org.apache.onami.persist.PersistenceUnitModule;
import uk.q3c.krail.i18n.PatternCacheKey;
import uk.q3c.krail.jpa.persist.BaseJpaKeyValueDao;

import javax.annotation.Nonnull;
import java.util.Optional;

/**
 * The default implementation of {@link JpaPatternDao}.  The {@code entityManagerProvider} and {@code dao} are bound by {@link PersistenceUnitModule} to the
 * annotation which is used in the injection of this class. (For example, if an instance of this class is annotated with @Jpa1, then the constructor parameters
 * will also be bound with @Jpa1)
 * <p>
 * Created by David Sowerby on 15/04/15.
 */
public class DefaultJpaPatternDao extends BaseJpaKeyValueDao<PatternId, PatternCacheKey, JpaPatternEntity> implements JpaPatternDao {


    @Inject
    protected DefaultJpaPatternDao(EntityManagerProvider entityManagerProvider) {
        super(entityManagerProvider, JpaPatternEntity.class);
    }


    @Override
    protected JpaPatternEntity newEntity(PatternCacheKey cacheKey, String value) {
        return new JpaPatternEntity(cacheKey, value);
    }

    @Override
    protected PatternId newId(PatternCacheKey cacheKey) {
        return new PatternId(cacheKey);
    }


    @Nonnull
    @Override
    public Optional<String> getValue(@Nonnull PatternCacheKey cacheKey) {
        return getValueAsString(cacheKey);
    }
}
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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.
    JpaPatternEntity find(PatternCacheKey cacheKey);
/*
 *
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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 uk.q3c.krail.jpa.i18n;

import uk.q3c.krail.i18n.PatternCacheKey;

import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Version;

/**
 * An entity to represent an I18N key, Locale and value combination
 * <p>
 * Created by David Sowerby on 15/04/15.
 */

@Entity
public class JpaPatternEntity implements KeyValueEntity<PatternId, Integer> {

    @EmbeddedId
    private PatternId id;
    private String value;
    @Version
    private Integer version;

    protected JpaPatternEntity() {
    }

    public JpaPatternEntity(PatternCacheKey cacheKey, String value) {
        id = new PatternId(cacheKey);
        this.value = value;
    }

    public String getI18nkey() {
        return id.getI18nkey();
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getLocale() {
        return id.getLocale();
    }

    @Override
    public PatternId getId() {
        return id;
    }

    @Override
    public Integer getVersion() {
        return version;
    }
}
/*
 *
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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 uk.q3c.krail.jpa.i18n;

import uk.q3c.krail.core.data.KrailEntity;

/**
 * Created by David Sowerby on 18 Jan 2016
 */
public interface KeyValueEntity<ID, VER> extends KrailEntity<ID, VER> {

    String getValue();

    void setValue(String value);
}
/*
 *
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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 uk.q3c.krail.jpa.i18n;

import uk.q3c.krail.core.data.EnumConverter;
import uk.q3c.krail.i18n.PatternCacheKey;

import javax.annotation.Nonnull;
import javax.persistence.Embeddable;

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

/**
 * Created by David Sowerby on 17 Jan 2016
 */
@Embeddable
public class PatternId {
    private String i18nkey;
    private String locale;

    protected PatternId() {

    }

    public PatternId(@Nonnull PatternCacheKey cacheKey) {
        checkNotNull(cacheKey);
        final Enum<?> enumKey = cacheKey.getKey();
        this.i18nkey = new EnumConverter().convertToString(enumKey);
        this.locale = cacheKey.getRequestedLocale()
                              .toLanguageTag();
    }

    public String getI18nkey() {
        return i18nkey;
    }

    public String getLocale() {
        return locale;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        PatternId that = (PatternId) o;

        if (!i18nkey.equals(that.i18nkey)) return false;
        return locale.equals(that.locale);

    }

    @Override
    public int hashCode() {
        int result = i18nkey.hashCode();
        return 31 * result + locale.hashCode();
    }
}
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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.
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
    @SuppressFBWarnings("SQL_INJECTION_JPA")
    // The only parameter is entityName(), which is limited to either the simple class name of the entity, or its annotation
    public final <E extends KrailEntity<ID, VER>> String entityName(@Nonnull Class<E> entityClass) {
     *

    @SuppressFBWarnings("SQL_INJECTION_JPA")
    // The only parameter is entityName(), which is limited to either the simple class name of the entity, or its annotation
/*
 *
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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 uk.q3c.krail.jpa.persist;

import org.apache.onami.persist.EntityManagerProvider;
import org.apache.onami.persist.Transactional;
import uk.q3c.krail.jpa.i18n.KeyValueEntity;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Optional;

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

/**
 * A common base class for Pattern and Option DAOs, which both require a key-value type of implementation
 * <p>
 * Created by David Sowerby on 18 Jan 2016
 */
public abstract class BaseJpaKeyValueDao<ID, K, E extends KeyValueEntity<ID, Integer>> extends BaseJpaDao<ID, Integer> implements JpaKeyValueDao<ID, Integer, K,
        E> {

    private Class<E> entityClass;

    public BaseJpaKeyValueDao(EntityManagerProvider entityManagerProvider, Class<E> entityClass) {
        super(entityManagerProvider);
        this.entityClass = entityClass;
    }

    @Transactional
    @Override
    public E write(@Nonnull K cacheKey, @Nonnull String value) {
        checkNotNull(cacheKey);
        checkNotNull(value);
        E existingEntity = find(cacheKey);
        if (existingEntity != null) {
            existingEntity.setValue(value);
            return save(existingEntity);
        } else {
            return save(newEntity(cacheKey, value));
        }
    }

    protected abstract E newEntity(K cacheKey, String value);

    protected abstract ID newId(K cacheKey);

    @Transactional
    @Override
    @Nullable
    public E find(@Nonnull K cacheKey) {
        checkNotNull(cacheKey);
        return getEntityManager().find(entityClass, newId(cacheKey));
    }

    @Transactional
    @Nonnull
    @Override
    public Optional<String> deleteValue(@Nonnull K cacheKey) {
        checkNotNull(cacheKey);
        Optional<E> deletedItem = deleteById(entityClass, newId(cacheKey));
        if (deletedItem.isPresent()) {
            return Optional.of(deletedItem.get()
                                          .getValue());
        } else {
            return Optional.empty();
        }
    }

    @Nonnull
    @Override
    public Optional<String> getValueAsString(@Nonnull K cacheKey) {
        checkNotNull(cacheKey);
        E entity = find(cacheKey);
        return (entity == null) ? Optional.empty() : Optional.of(entity.getValue());
    }

    /**
     * returns the number of entries
     *
     * @return the number of entries
     */
    @Override
    @Transactional
    public long count() {
        return super.count(entityClass);
    }

}
import uk.q3c.krail.jpa.i18n.DefaultJpaPatternDao;
import uk.q3c.krail.jpa.user.opt.DefaultJpaOptionDao;
        bind(OptionDao.class, DefaultJpaOptionDao.class);
        bind(PatternDao.class, DefaultJpaPatternDao.class);
/*
 *
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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 uk.q3c.krail.jpa.persist;

import org.apache.onami.persist.Transactional;
import uk.q3c.krail.jpa.i18n.KeyValueEntity;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Optional;

/**
 * Created by David Sowerby on 18 Jan 2016
 */
public interface JpaKeyValueDao<ID, VER, K, E extends KeyValueEntity> extends JpaDao<ID, VER> {
    @Transactional
    E write(@Nonnull K cacheKey, @Nonnull String value);

    @Transactional
    @Nullable
    E find(@Nonnull K cacheKey);

    @Transactional
    @Nonnull
    Optional<String> deleteValue(@Nonnull K cacheKey);

    @Nonnull
    Optional<String> getValueAsString(@Nonnull K cacheKey);

    @Transactional
    long count();
}
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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.
        return jpaContainerProvider.get(JpaOptionEntity.class, containerType);
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import uk.q3c.krail.jpa.persist.BaseJpaKeyValueDao;
import static com.google.common.base.Preconditions.checkArgument;
 * Converts {@link OptionCacheKey} to {@link JpaOptionEntity} for persistence.
public class DefaultJpaOptionDao extends BaseJpaKeyValueDao<OptionId, OptionCacheKey, JpaOptionEntity> implements JpaOptionDao {
    protected DefaultJpaOptionDao(EntityManagerProvider entityManagerProvider, OptionStringConverter optionStringConverter) {
        super(entityManagerProvider, JpaOptionEntity.class);
        return new Select().from(entityName(JpaOptionEntity.class))

    @Override
    public <V> Object write(@Nonnull OptionCacheKey cacheKey, @Nonnull Optional<V> value) {
        checkRankOption(cacheKey, SPECIFIC_RANK);
        checkArgument(value.isPresent(), "Value must be present");
        String stringValue = optionStringConverter.convertValueToString(value.get());
        return write(cacheKey, stringValue);
    }

        Optional<String> v = getValueAsString(cacheKey);
        return (v.isPresent()) ? Optional.of(optionStringConverter.convertStringToValue(cacheKey, v.get())) : Optional.empty();
    @SuppressFBWarnings("SQL_INJECTION_JPA")//entityName() is final and can only return SimpleClassName of annotation
    @SuppressWarnings("JpaQlInspection")
        return getEntityManager().createQuery("DELETE FROM " + entityName(JpaOptionEntity.class))
                                 .executeUpdate();
    }

    @Override
    protected JpaOptionEntity newEntity(OptionCacheKey cacheKey, String value) {
        return new JpaOptionEntity(cacheKey, value);
    }

    @Override
    protected OptionId newId(OptionCacheKey cacheKey) {
        return new OptionId(cacheKey);
        return super.count(JpaOptionEntity.class);
/*
 *
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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 uk.q3c.krail.jpa.user.opt;

import org.apache.onami.persist.Transactional;
import uk.q3c.krail.core.user.opt.OptionDao;
import uk.q3c.krail.core.user.opt.cache.OptionCacheKey;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/**
 * Created by David Sowerby on 13/04/15.
 */
public interface JpaOptionDao extends OptionDao {

    @Transactional
    @Nullable
    JpaOptionEntity find(@Nonnull OptionCacheKey cacheKey);
}
/*
 *
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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 uk.q3c.krail.jpa.user.opt;

import uk.q3c.krail.core.user.opt.Option;
import uk.q3c.krail.core.user.opt.cache.OptionCacheKey;
import uk.q3c.krail.jpa.i18n.KeyValueEntity;

import javax.annotation.Nonnull;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Version;

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

/**
 * An entity to hold data for an {@link Option}.  The value is held as a String to enable the use of a single column for it.  Context is part of the overall
 * {#optionKey} to ensure uniqueness, but is also held separately as it is a useful way to group the options for manual setting up, and there may also be an
 * opportunity to pre-load options by Context.
 * <p>
 * Created by David Sowerby on 13/04/15.
 */
@Entity
public class JpaOptionEntity implements KeyValueEntity<OptionId, Integer> {

    @EmbeddedId
    private OptionId id;
    private String value;
    @Version
    private Integer version;

    protected JpaOptionEntity() {
    }

    public JpaOptionEntity(@Nonnull OptionCacheKey optionCacheKey, @Nonnull String value) {
        this.id = new OptionId(optionCacheKey);
        this.value = value;

    }

    @Override
    public OptionId getId() {
        return id;
    }

    @Override
    public Integer getVersion() {
        return version;
    }

    public String getContext() {
        return id.getContext();
    }

    public String getUserHierarchyName() {
        return id.getUserHierarchyName();
    }

    public String getRankName() {
        return id.getRankName();
    }

    public String getOptionKey() {
        return id.getOptionKey();
    }

    @Nonnull
    public String getValue() {
        return value;
    }

    public void setValue(@Nonnull String value) {
        checkNotNull(value);
        this.value = value;
    }


}
/*
 *
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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 uk.q3c.krail.jpa.user.opt;

import uk.q3c.krail.core.user.opt.cache.OptionCacheKey;

import javax.persistence.Embeddable;

/**
 * Created by David Sowerby on 17 Jan 2016
 */
@Embeddable
public class OptionId {


    private String context;
    private String optionKey;
    private String rankName;
    private String userHierarchyName;

    protected OptionId() {

    }

    public OptionId(OptionCacheKey optionCacheKey) {
        userHierarchyName = optionCacheKey.getHierarchy()
                                          .persistenceName();
        rankName = optionCacheKey.getRequestedRankName();
        optionKey = optionCacheKey.getOptionKey()
                                  .compositeKey();
        context = optionCacheKey.getOptionKey()
                                .getContext()
                                .getName();
    }

    public String getContext() {
        return context;
    }

    public String getOptionKey() {
        return optionKey;
    }

    public String getRankName() {
        return rankName;
    }

    public String getUserHierarchyName() {
        return userHierarchyName;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        OptionId optionId = (OptionId) o;

        if (context != null ? !context.equals(optionId.context) : optionId.context != null) return false;
        if (optionKey != null ? !optionKey.equals(optionId.optionKey) : optionId.optionKey != null) return false;
        if (rankName != null ? !rankName.equals(optionId.rankName) : optionId.rankName != null) return false;
        return userHierarchyName != null ? userHierarchyName.equals(optionId.userHierarchyName) : optionId.userHierarchyName == null;

    }

    @Override
    public int hashCode() {
        int result = context != null ? context.hashCode() : 0;
        result = 31 * result + (optionKey != null ? optionKey.hashCode() : 0);
        result = 31 * result + (rankName != null ? rankName.hashCode() : 0);
        return 31 * result + (userHierarchyName != null ? userHierarchyName.hashCode() : 0);
    }
}
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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.
class DefaultJpaPatternDao__IntegrationTest extends Specification {
        persistenceService.isRunning()
        unitOfWork.isActive()
        JpaPatternEntity actual = dao.find(cacheKey)
        actual != null
        actual.getValue() == "4"
        JpaPatternEntity actual = dao.find(cacheKey)
        actual != null
        actual.getValue() == "6"
        JpaPatternEntity result2 = dao.find(cacheKey2)
        JpaPatternEntity result3 = dao.find(cacheKey3)
        result2.getValue() == "4"
        result3.getValue() == "5"
/*
 *
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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 uk.q3c.krail.jpa.i18n

import spock.lang.Specification
import uk.q3c.krail.i18n.LabelKey
import uk.q3c.krail.i18n.PatternCacheKey

/**
 * Created by David Sowerby on 13/07/15.
 */
class JpaPatternEntity_Test extends Specification {


    JpaPatternEntity entity;

    def "create decodes the I18NKey"() {
        given:

        PatternCacheKey cacheKey1 = new PatternCacheKey(LabelKey.Yes, Locale.UK)

        when:

        entity = new JpaPatternEntity(cacheKey1, "x")


        then:

        entity.getI18nkey().equals("uk.q3c.krail.i18n.LabelKey.Yes")
    }
}
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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.
import uk.q3c.krail.jpa.i18n.DefaultJpaPatternDao;
import uk.q3c.krail.jpa.user.opt.DefaultJpaOptionDao;
import uk.q3c.krail.jpa.user.opt.JpaOptionDao;
                      bind(JpaOptionDao.class, DefaultJpaOptionDao.class)
              .bind(JpaPatternDao.class, DefaultJpaPatternDao.class);
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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.
 * Test for {@link DefaultJpaOptionDao}
class DefaultJpaOptionDaoTest extends Specification {
    TypedQuery<JpaOptionEntity> query = Mock()
    List<JpaOptionEntity> emptyResultList;
    DefaultJpaOptionDao dao
        dao = new DefaultJpaOptionDao(entityManagerProvider, stringPersistenceConverter)
        entity instanceof JpaOptionEntity
        JpaOptionEntity rEntity = (JpaOptionEntity) entity
        List<JpaOptionEntity> resultList = new ArrayList<>();
        resultList.add((JpaOptionEntity) entity)
        entity instanceof JpaOptionEntity
        JpaOptionEntity rEntity = (JpaOptionEntity) entity
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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.
class DefaultJpaOptionDao__DataTypeTest extends Specification {
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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.
class DefaultJpaOptionDao__IntegrationTest extends Specification {
        JpaOptionEntity actual = (JpaOptionEntity) dao.write(cacheKey, Optional.of("4"));
        JpaOptionEntity actual = (JpaOptionEntity) dao.write(cacheKey, Optional.of("4"));
        actual = (JpaOptionEntity) dao.write(cacheKey, Optional.of("5"));
        actual = (JpaOptionEntity) dao.write(cacheKey, Optional.of("6"));
        JpaOptionEntity result = dao.find(cacheKey)
        result != null
        result.getValue() == "6"
        JpaOptionEntity result1 = dao.find(cacheKey1)
        JpaOptionEntity result2 = dao.find(cacheKey2)
        result1.getValue() == "4"
        result2.getValue() == "5"
 *  * Copyright (c) 2016. David Sowerby
 *  *
 *  * 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.
public class DefaultOptionJpaDaoTest2 extends JpaDaoTestBase {
    JpaOptionDao dao;
        final Key<JpaOptionDao> daoKey = Key.get(JpaOptionDao.class, Jpa1.class);
  ~ /*
  ~  * Copyright (c) 2016. David Sowerby
  ~  *
  ~  * 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.
  ~  */
        <class>uk.q3c.krail.jpa.user.opt.JpaOptionEntity</class>
        <class>uk.q3c.krail.jpa.i18n.JpaPatternEntity</class>
        <class>uk.q3c.krail.jpa.user.opt.JpaOptionEntity</class>
        <class>uk.q3c.krail.jpa.i18n.JpaPatternEntity</class>
        <class>uk.q3c.krail.jpa.user.opt.JpaOptionEntity</class>
        <class>uk.q3c.krail.jpa.i18n.JpaPatternEntity</class>
        <class>uk.q3c.krail.jpa.user.opt.JpaOptionEntity</class>
        <class>uk.q3c.krail.jpa.i18n.JpaPatternEntity</class>