diff options
17 files changed, 1031 insertions, 115 deletions
diff --git a/models-base/src/main/java/org/onap/policy/models/base/PfGeneratedIdKey.java b/models-base/src/main/java/org/onap/policy/models/base/PfGeneratedIdKey.java new file mode 100644 index 000000000..8e6e325c1 --- /dev/null +++ b/models-base/src/main/java/org/onap/policy/models/base/PfGeneratedIdKey.java @@ -0,0 +1,166 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.models.base; + + +import javax.persistence.Column; +import javax.persistence.Embeddable; +import javax.persistence.GeneratedValue; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NonNull; +import org.onap.policy.common.parameters.annotations.Pattern; +import org.onap.policy.common.utils.validation.Assertions; + +/** + * A concept key uniquely identifies every first order entity in the system. Every first order concept in the system + * must have a {@link PfGeneratedIdKey} to identify it. Concepts that are wholly contained in another concept are + * identified using a {@link PfReferenceKey} key. + * + * <p/>Key validation checks that the name and version fields match the NAME_REGEXP and VERSION_REGEXP + * regular expressions respectively. + */ +@Embeddable +@Data +@EqualsAndHashCode(callSuper = false) +public class PfGeneratedIdKey extends PfKeyImpl { + + private static final long serialVersionUID = 1L; + + private static final String ID_TOKEN = "ID"; + + @Column(name = NAME_TOKEN, length = 120) + @Pattern(regexp = NAME_REGEXP) + private String name; + + @Column(name = VERSION_TOKEN, length = 20) + @Pattern(regexp = VERSION_REGEXP) + private String version; + + @Column(name = ID_TOKEN) + @GeneratedValue + private Long generatedId; + + /** + * The default constructor creates a null concept key. + */ + public PfGeneratedIdKey() { + this(NULL_KEY_NAME, NULL_KEY_VERSION); + } + + /** + * Constructor to create a key with the specified name and version. + * + * @param name the key name + * @param version the key version + */ + public PfGeneratedIdKey(final String name, final String version) { + super(name, version); + } + + /** + * Copy constructor. + * + * @param copyConcept the concept to copy from + */ + public PfGeneratedIdKey(final PfGeneratedIdKey copyConcept) { + super(copyConcept); + this.generatedId = copyConcept.getGeneratedId(); + } + + /** + * Constructor to create a key with the specified name and version. + * + * @param name the key name + * @param version the key version + * @param generatedId the conceptId of key + */ + public PfGeneratedIdKey(@NonNull final String name, @NonNull final String version, + final Long generatedId) { + super(name, version); + this.generatedId = generatedId; + } + + /** + * Constructor to create a key using the key and version from the specified key ID. + * + * @param id the key ID in a format that respects the KEY_ID_REGEXP + */ + public PfGeneratedIdKey(final String id) { + super(id.substring(0, id.lastIndexOf(':'))); + this.generatedId = Long.parseLong(id.substring(id.lastIndexOf(':') + 1)); + } + + @Override + public int compareTo(@NonNull final PfConcept otherObj) { + int result = super.compareTo(otherObj); + if (0 == result) { + final PfGeneratedIdKey other = (PfGeneratedIdKey) otherObj; + return generatedId.compareTo(other.generatedId); + } + return result; + } + + @Override + public String getId() { + return getName() + ':' + getVersion() + ':' + getGeneratedId(); + } + + @Override + public boolean isNewerThan(@NonNull PfKey otherKey) { + Assertions.instanceOf(otherKey, PfGeneratedIdKey.class); + + final PfGeneratedIdKey otherConceptKey = (PfGeneratedIdKey) otherKey; + + if (this.equals(otherConceptKey)) { + return false; + } + + if (!generatedId.equals(otherConceptKey.generatedId)) { + return generatedId.compareTo(otherConceptKey.generatedId) >= 1; + } + + return super.isNewerThan(otherKey); + } + + @Override + public boolean isNullKey() { + return super.isNullKey() && getGeneratedId() == null; + } + + public void setName(@NonNull final String name) { + this.name = Assertions.validateStringParameter(NAME_TOKEN, name, getNameRegEx()); + } + + public void setVersion(@NonNull final String version) { + this.version = Assertions.validateStringParameter(VERSION_TOKEN, version, getVersionRegEx()); + } + + /** + * Get a null concept key. + * + * @return a null concept key + */ + public static final PfGeneratedIdKey getNullKey() { + return new PfGeneratedIdKey(PfKey.NULL_KEY_NAME, PfKey.NULL_KEY_VERSION); + } + +} diff --git a/models-base/src/test/java/org/onap/policy/models/base/PfGeneratedIdKeyTest.java b/models-base/src/test/java/org/onap/policy/models/base/PfGeneratedIdKeyTest.java new file mode 100644 index 000000000..4f10710ba --- /dev/null +++ b/models-base/src/test/java/org/onap/policy/models/base/PfGeneratedIdKeyTest.java @@ -0,0 +1,96 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + + +package org.onap.policy.models.base; + +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class PfGeneratedIdKeyTest { + private static final String VERSION001 = "0.0.1"; + private static final String CONCEPT_IS_NULL = "^copyConcept is marked .*on.*ull but is null$"; + private static final String NAME_IS_NULL = "^name is marked .*on.*ull but is null$"; + private static final String VERSION_IS_NULL = "^version is marked .*on.*ull but is null$"; + private static final long generatedId = 10001L; + + @Test + public void testGeneratedIdKey() { + PfGeneratedIdKey someKey0 = new PfGeneratedIdKey(); + assertEquals(PfGeneratedIdKey.getNullKey(), someKey0); + assertTrue(someKey0.isNullKey()); + assertEquals("PfGeneratedIdKey(name=NULL, version=0.0.0, generatedId=null)", + someKey0.toString()); + + PfGeneratedIdKey someKey1 = new PfGeneratedIdKey("my-name", VERSION001, generatedId); + PfGeneratedIdKey someKey2 = new PfGeneratedIdKey(someKey1); + PfGeneratedIdKey someKey3 = new PfGeneratedIdKey(someKey1.getId()); + assertEquals(someKey1, someKey2); + assertEquals(someKey1, someKey3); + assertFalse(someKey1.isNullVersion()); + assertEquals("PfGeneratedIdKey(name=my-name, version=0.0.1, generatedId=" + + generatedId + ")", someKey1.toString()); + + assertEquals("my-name", someKey1.getName()); + assertEquals(VERSION001, someKey1.getVersion()); + + assertEquals(someKey2, someKey1.getKey()); + assertEquals(1, someKey1.getKeys().size()); + assertThatThrownBy(() -> someKey0.setName(null)).isInstanceOf(NullPointerException.class) + .hasMessageMatching(NAME_IS_NULL); + assertThatThrownBy(() -> someKey0.setVersion(null)).isInstanceOf(NullPointerException.class) + .hasMessageMatching(VERSION_IS_NULL); + assertThatCode(() -> someKey0.setGeneratedId(null)).doesNotThrowAnyException(); + + assertFalse(someKey1.isNewerThan(someKey2)); + assertThatThrownBy(() -> someKey1.isNewerThan((PfKey) null)).isInstanceOf(NullPointerException.class) + .hasMessageMatching("^otherKey is marked .*on.*ull but is null$"); + someKey2.setGeneratedId(generatedId + 1); + assertTrue(someKey2.isNewerThan(someKey1)); + someKey3.setName("my-name3"); + assertTrue(someKey3.isNewerThan(someKey1)); + + assertEquals(-1, someKey1.compareTo(someKey2)); + assertEquals(-1, someKey1.compareTo(someKey3)); + assertThatThrownBy(() -> someKey1.compareTo((PfConcept) null)).isInstanceOf(NullPointerException.class) + .hasMessageMatching("^otherObj is marked .*on.*ull but is null$"); + + PfGeneratedIdKey someKey4 = new PfGeneratedIdKey("NULL", "0.0.0", generatedId); + assertFalse(someKey4.isNullKey()); + assertFalse(someKey1.isNullKey()); + } + + @Test + public void testTimestampKeyErrors() { + assertThatThrownBy(() -> new PfGeneratedIdKey((PfGeneratedIdKey) null)).isInstanceOf(NullPointerException.class) + .hasMessageMatching(CONCEPT_IS_NULL); + assertThatThrownBy(() -> new PfGeneratedIdKey(null, null, null)).isInstanceOf(NullPointerException.class) + .hasMessageMatching(NAME_IS_NULL); + assertThatThrownBy(() -> new PfGeneratedIdKey("my-name", null, null)).isInstanceOf(NullPointerException.class) + .hasMessageMatching(VERSION_IS_NULL); + assertThatCode(() -> new PfGeneratedIdKey("my-name", VERSION001, null)) + .doesNotThrowAnyException(); + } +} diff --git a/models-dao/src/main/java/org/onap/policy/models/dao/PfDao.java b/models-dao/src/main/java/org/onap/policy/models/dao/PfDao.java index eb77be9c0..844759367 100644 --- a/models-dao/src/main/java/org/onap/policy/models/dao/PfDao.java +++ b/models-dao/src/main/java/org/onap/policy/models/dao/PfDao.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Map; import org.onap.policy.models.base.PfConcept; import org.onap.policy.models.base.PfConceptKey; +import org.onap.policy.models.base.PfGeneratedIdKey; import org.onap.policy.models.base.PfModelException; import org.onap.policy.models.base.PfReferenceKey; import org.onap.policy.models.base.PfReferenceTimestampKey; @@ -95,6 +96,15 @@ public interface PfDao { <T extends PfConcept> void delete(Class<T> someClass, PfTimestampKey timeStampKey); /** + * Delete an Policy Framework concept on the database. + * + * @param <T> the type of the object to delete, a subclass of {@link PfConcept} + * @param someClass the class of the object to delete, a subclass of {@link PfConcept} + * @param idKey the PfConceptIdKey of the object to delete + */ + <T extends PfConcept> void delete(Class<T> someClass, PfGeneratedIdKey idKey); + + /** * Create a collection of objects in the database. * * @param <T> the type of the object to create, a subclass of {@link PfConcept} @@ -203,6 +213,16 @@ public interface PfDao { <T extends PfConcept> T get(Class<T> someClass, PfTimestampKey timestampKey); /** + * Get an object from the database, referred to by reference key. + * + * @param <T> the type of the object to get, a subclass of {@link PfConcept} + * @param someClass the class of the object to get, a subclass of {@link PfConcept} + * @param idKey the PfConceptIdKey of the object to get + * @return the object that was retrieved from the database or null if the object was not retrieved + */ + <T extends PfConcept> T get(Class<T> someClass, PfGeneratedIdKey idKey); + + /** * Get an object from the database, referred to by reference timestamp key. * * @param <T> the type of the object to get, a subclass of {@link PfConcept} @@ -252,6 +272,18 @@ public interface PfDao { <T extends PfConcept> List<T> getAllVersionsByParent(Class<T> someClass, final String parentKeyName); /** + * Get all the objects in the database of a given type. + * + * @param <T> the type of the objects to get, a subclass of {@link PfConcept} + * @param someClass the class of the objects to get, a subclass of {@link PfConcept} + * @param key the key of the PfGeneratedIdKey to get + * @param timeStamp the timeStamp of the concepts to get + * @return the objects or null if no objects were retrieved + */ + <T extends PfConcept> List<T> getByTimestamp(final Class<T> someClass, + final PfGeneratedIdKey key, final Instant timeStamp); + + /** * Get a concept from the database with the given concept key. * * @param <T> the type of the object to get, a subclass of {@link PfConcept} diff --git a/models-dao/src/main/java/org/onap/policy/models/dao/PfFilter.java b/models-dao/src/main/java/org/onap/policy/models/dao/PfFilter.java new file mode 100644 index 000000000..ef9d4f939 --- /dev/null +++ b/models-dao/src/main/java/org/onap/policy/models/dao/PfFilter.java @@ -0,0 +1,91 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.models.dao; + +import java.time.Instant; +import java.util.Map; +import lombok.Data; +/** + * This abstract class is used as a base for the filter implementations. + * + */ + +@Data +public abstract class PfFilter { + private static final String AND = " AND "; + private static final String ORDER = " ORDER BY "; + + private String nameFilter; + private String timeStampStartFilter; + private String timeStampEndFilter; + private String timeStampFilter; + private String nameParameter; + + /** + * Generates filter string. + * + * @param inputFilterString current filterString generated from FilterMap + * @param name the pdpInstance name for the PDP statistics to get + * @param startTime the start timeStamp to filter from database, filter rule: + * startTime <= filteredRecord timeStamp <= endTime. null for ignore end time + * @param endTime the end timeStamp to filter from database, filter rule: + * startTime <= filteredRecord timeStamp <= endTime. null for ignore end time + * @param filterMap Map store extra key/value used to filter from database, can be null * + * @param sortOrder sortOrder to query database + * @param getRecordNum Total query count from database + + */ + public String addFilter(final String inputFilterString, + final String name, final Instant startTime, final Instant endTime, + final Map<String, Object> filterMap, final String sortOrder, final int getRecordNum) { + StringBuilder filterQueryString = new StringBuilder(inputFilterString); + if (filterMap != null) { + for (String key : filterMap.keySet()) { + filterQueryString.append("c." + key + "= :" + key + AND); + } + } + + if (name != null) { + filterQueryString.append(getNameFilter() + AND); + } + + if (startTime != null) { + if (endTime != null) { + filterQueryString.append(getTimeStampStartFilter()); + filterQueryString.append(AND); + filterQueryString.append(getTimeStampEndFilter()); + } else { + filterQueryString.append(getTimeStampStartFilter()); + } + } else { + if (endTime != null) { + filterQueryString.append(getTimeStampEndFilter()); + } else { + filterQueryString.delete(filterQueryString.length() - AND.length(), filterQueryString.length()); + } + } + + if (getRecordNum > 0) { + filterQueryString.append(ORDER + getTimeStampFilter() + sortOrder); + } + return filterQueryString.toString(); + } +} diff --git a/models-dao/src/main/java/org/onap/policy/models/dao/PfFilterFactory.java b/models-dao/src/main/java/org/onap/policy/models/dao/PfFilterFactory.java new file mode 100644 index 000000000..643481f39 --- /dev/null +++ b/models-dao/src/main/java/org/onap/policy/models/dao/PfFilterFactory.java @@ -0,0 +1,77 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.models.dao; + +import java.time.Instant; +import java.util.Map; +import org.onap.policy.models.base.PfConcept; +import org.onap.policy.models.dao.impl.PfNonTimestampKeyFilter; +import org.onap.policy.models.dao.impl.PfReferenceTimestampKeyFilter; +import org.onap.policy.models.dao.impl.PfTimestampKeyFilter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This factory class creates a filter class for a key type. + * The filter returned depends on the type of class being used. + * + */ +public class PfFilterFactory { + // Get a reference to the logger + private static final Logger LOGGER = LoggerFactory.getLogger(PfFilterFactory.class); + + /** + * Return a filter class for the input class. + * + * @param <T> the type of the object to get, a subclass of {@link PfConcept}* + * @return the filter type for the input class * + */ + public <T extends PfConcept> PfFilter createFilter(final Class<T> someClass) { + PfFilter filter = null; + + switch (getKeyName(someClass)) { + case "PfTimestampKey": + filter = new PfTimestampKeyFilter(); + break; + case "PfReferenceTimestampKey": + filter = new PfReferenceTimestampKeyFilter(); + break; + default: + filter = new PfNonTimestampKeyFilter(); + } + return filter; + } + + /** + * Gets the name of the key class of the class invoking the DAO. + * @param someClass class that invoked Dao + * @return the name of the key class + */ + private <T extends PfConcept> String getKeyName(final Class<T> someClass) { + try { + String fullClassName = someClass.getDeclaredField("key").getType().toString(); + return fullClassName.substring(fullClassName.lastIndexOf('.') + 1); + } catch (NoSuchFieldException e) { + LOGGER.error("Error getting the key:", e); + return "NON_TIMESTAMP_KEY"; + } + } +} diff --git a/models-dao/src/main/java/org/onap/policy/models/dao/impl/DefaultPfDao.java b/models-dao/src/main/java/org/onap/policy/models/dao/impl/DefaultPfDao.java index bdbc04e22..1bd2e09da 100644 --- a/models-dao/src/main/java/org/onap/policy/models/dao/impl/DefaultPfDao.java +++ b/models-dao/src/main/java/org/onap/policy/models/dao/impl/DefaultPfDao.java @@ -34,6 +34,7 @@ import javax.persistence.TypedQuery; import javax.ws.rs.core.Response; import org.onap.policy.models.base.PfConcept; import org.onap.policy.models.base.PfConceptKey; +import org.onap.policy.models.base.PfGeneratedIdKey; import org.onap.policy.models.base.PfModelException; import org.onap.policy.models.base.PfModelRuntimeException; import org.onap.policy.models.base.PfReferenceKey; @@ -42,6 +43,8 @@ import org.onap.policy.models.base.PfTimestampKey; import org.onap.policy.models.base.PfUtils; import org.onap.policy.models.dao.DaoParameters; import org.onap.policy.models.dao.PfDao; +import org.onap.policy.models.dao.PfFilter; +import org.onap.policy.models.dao.PfFilterFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,6 +59,7 @@ public class DefaultPfDao implements PfDao { private static final String NAME = "name"; private static final String VERSION = "version"; private static final String TIMESTAMP = "timeStamp"; + private static final String GENERATEDID = "Id"; private static final String PARENT_NAME = "parentname"; private static final String PARENT_VERSION = "parentversion"; private static final String LOCAL_NAME = "localname"; @@ -73,8 +77,8 @@ public class DefaultPfDao implements PfDao { private static final String NAME_FILTER = "c.key.name = :name"; private static final String VERSION_FILTER = "c.key.version = :version"; private static final String TIMESTAMP_FILTER = "c.key.timeStamp = :timeStamp"; - private static final String TIMESTAMP_START_FILTER = "c.key.timeStamp >= :startTime"; - private static final String TIMESTAMP_END_FILTER = "c.key.timeStamp <= :endTime"; + private static final String TIMESTAMP_FILTER_NOKEY = "c.timeStamp = :timeStamp"; + private static final String GENERATED_ID_FILTER = "c.key.generatedId = :Id"; private static final String PARENT_NAME_FILTER = "c.key.parentKeyName = :parentname"; private static final String PARENT_VERSION_FILTER = "c.key.parentKeyVersion = :parentversion"; private static final String LOCAL_NAME_FILTER = "c.key.localName = :localname"; @@ -89,6 +93,9 @@ public class DefaultPfDao implements PfDao { private static final String DELETE_BY_TIMESTAMP_KEY = DELETE_FROM_TABLE + WHERE + NAME_FILTER + AND + VERSION_FILTER + AND + TIMESTAMP_FILTER; + private static final String DELETE_BY_GENERATED_ID_KEY = + DELETE_FROM_TABLE + WHERE + NAME_FILTER + AND + VERSION_FILTER + AND + GENERATED_ID_FILTER; + private static final String DELETE_BY_REFERENCE_KEY = DELETE_FROM_TABLE + WHERE + PARENT_NAME_FILTER + AND + PARENT_VERSION_FILTER + AND + LOCAL_NAME_FILTER; @@ -103,6 +110,9 @@ public class DefaultPfDao implements PfDao { private static final String SELECT_BY_CONCEPT_KEY = SELECT_FROM_TABLE + WHERE + NAME_FILTER + AND + VERSION_FILTER; + private static final String SELECT_BY_TIMESTAMP_NOKEY = + SELECT_FROM_TABLE + WHERE + NAME_FILTER + AND + VERSION_FILTER + AND + TIMESTAMP_FILTER_NOKEY; + private static final String SELECT_BY_REFERENCE_KEY = SELECT_FROM_TABLE + WHERE + PARENT_NAME_FILTER + AND + PARENT_VERSION_FILTER + AND + LOCAL_NAME_FILTER; // @formatter:on @@ -246,6 +256,27 @@ public class DefaultPfDao implements PfDao { } @Override + public <T extends PfConcept> void delete(final Class<T> someClass, final PfGeneratedIdKey key) { + if (key == null) { + return; + } + final EntityManager mg = getEntityManager(); + try { + // @formatter:off + mg.getTransaction().begin(); + mg.createQuery(setQueryTable(DELETE_BY_GENERATED_ID_KEY, someClass), someClass) + .setParameter(NAME, key.getName()) + .setParameter(VERSION, key.getVersion()) + .setParameter(GENERATEDID, key.getGeneratedId()) + .executeUpdate(); + mg.getTransaction().commit(); + // @formatter:on + } finally { + mg.close(); + } + } + + @Override public <T extends PfConcept> void createCollection(final Collection<T> objs) { if (objs == null || objs.isEmpty()) { return; @@ -366,14 +397,11 @@ public class DefaultPfDao implements PfDao { String filterQueryString = SELECT_FROM_TABLE + WHERE; try { - if (filterMap != null) { - filterQueryString = buildFilter(filterMap, filterQueryString, isRefTimestampKey(someClass)); - } - filterQueryString = addKeyFilterString(filterQueryString, name, startTime, endTime, - isRefTimestampKey(someClass)); - if (getRecordNum > 0) { - filterQueryString += ORDER + " c.key.timeStamp " + sortOrder; - } + PfFilter timeStampFilter = new PfFilterFactory().createFilter(someClass); + filterQueryString = timeStampFilter.addFilter(filterQueryString, + name, startTime, endTime, filterMap, sortOrder, getRecordNum); + + TypedQuery<T> query = mg.createQuery(setQueryTable(filterQueryString, someClass), someClass); if (filterMap != null) { @@ -382,11 +410,7 @@ public class DefaultPfDao implements PfDao { } } if (name != null) { - if (isRefTimestampKey(someClass)) { - query.setParameter("parentKeyName", name); - } else { - query.setParameter("name", name); - } + query.setParameter(timeStampFilter.getNameParameter(), name); } if (startTime != null) { if (endTime != null) { @@ -411,33 +435,6 @@ public class DefaultPfDao implements PfDao { } } - /** - * This method checks if the class invoking the DAO is using PfReferenceTimestamp Key. - * @param someClass class that invoked Dao - * @return true if the key is PfReferenceTimestampKey. - */ - private <T extends PfConcept> boolean isRefTimestampKey(final Class<T> someClass) { - try { - return PfReferenceTimestampKey.class.isAssignableFrom(someClass.getDeclaredField("key").getType()); - } catch (NoSuchFieldException e) { - LOGGER.error("Error verifying the key for reference timestamp:", e); - return false; - } - } - - private String buildFilter(final Map<String, Object> filterMap, String filterQueryString, - boolean isRefTimestampKey) { - StringBuilder bld = new StringBuilder(filterQueryString); - for (String key : filterMap.keySet()) { - if (isRefTimestampKey) { - bld.append("c.key.referenceKey." + key + "= :" + key + AND); - } else { - bld.append("c." + key + "= :" + key + AND); - } - } - return bld.toString(); - } - @Override public <T extends PfConcept> T get(final Class<T> someClass, final PfConceptKey key) { return genericGet(someClass, key); @@ -449,6 +446,11 @@ public class DefaultPfDao implements PfDao { } @Override + public <T extends PfConcept> T get(final Class<T> someClass, final PfGeneratedIdKey key) { + return genericGet(someClass, key); + } + + @Override public <T extends PfConcept> T get(final Class<T> someClass, final PfTimestampKey key) { return genericGet(someClass, key); } @@ -540,6 +542,28 @@ public class DefaultPfDao implements PfDao { } @Override + public <T extends PfConcept> List<T> getByTimestamp(final Class<T> someClass, + final PfGeneratedIdKey key, + final Instant timeStamp) { + if (someClass == null || key == null || timeStamp == null) { + return Collections.emptyList(); + } + + final EntityManager mg = getEntityManager(); + try { + // @formatter:off + return mg.createQuery(setQueryTable(SELECT_BY_TIMESTAMP_NOKEY, someClass), someClass) + .setParameter(NAME, key.getName()) + .setParameter(VERSION, key.getVersion()) + .setParameter(TIMESTAMP, Timestamp.from(timeStamp)) + .getResultList(); + // @formatter:on + } finally { + mg.close(); + } + } + + @Override public <T extends PfConcept> T getConcept(final Class<T> someClass, final PfConceptKey key) { if (someClass == null || key == null) { return null; @@ -644,45 +668,6 @@ public class DefaultPfDao implements PfDao { } /** - * generate filter string with the filter value in TimestampKey. - * - * @param inputFilterString current filterString generated from FilterMap - * @param name the pdp name the start timeStamp to filter from database, filter rule: startTime <= filteredRecord - * timeStamp <= endTime. null for ignore start time. - * @param endTime the end timeStamp to filter from database, filter rule: startTime <= filteredRecord timeStamp <= - * endTime. null for ignore end time - * @param isRefTimestampKey boolean value, set to true if the query invoked for pfReferenceTimestampKey - * @return the filter string to query database - */ - private String addKeyFilterString(String inputFilterString, final String name, final Instant startTime, - final Instant endTime, final boolean isRefTimestampKey) { - String filterQueryString; - String inputFilter = inputFilterString; - if (name != null) { - if (isRefTimestampKey) { - inputFilter += PARENT_NAME_REF_FILTER + AND; - } else { - inputFilter += NAME_FILTER + AND; - } - } - if (startTime != null) { - if (endTime != null) { - filterQueryString = inputFilter + TIMESTAMP_START_FILTER + AND + TIMESTAMP_END_FILTER; - } else { - filterQueryString = inputFilter + TIMESTAMP_START_FILTER; - } - } else { - if (endTime != null) { - filterQueryString = inputFilter + TIMESTAMP_END_FILTER; - } else { - filterQueryString = inputFilter.substring(0, inputFilter.length() - AND.length()); - } - } - - return filterQueryString; - } - - /** * check the result get from database and return the object. * * @param <T> the type of the object to get, a subclass of {@link PfConcept} diff --git a/models-dao/src/main/java/org/onap/policy/models/dao/impl/PfNonTimestampKeyFilter.java b/models-dao/src/main/java/org/onap/policy/models/dao/impl/PfNonTimestampKeyFilter.java new file mode 100644 index 000000000..9c9a3e844 --- /dev/null +++ b/models-dao/src/main/java/org/onap/policy/models/dao/impl/PfNonTimestampKeyFilter.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.models.dao.impl; + +import org.onap.policy.models.dao.PfFilter; + +/** + * This class is used to set the values for a non timeStamp key query. + * + */ +public class PfNonTimestampKeyFilter extends PfFilter { + private static final String NAME_FILTER = "c.key.name = :name"; + private static final String TIMESTAMP_START_FILTER = "c.timeStamp >= :startTime"; + private static final String TIMESTAMP_END_FILTER = "c.timeStamp <= :endTime"; + private static final String TIMESTAMP_FILTER = " c.timeStamp "; + private static final String NAME_PARAMETER = "name"; + + /** + * The default constructor injects query strings. + */ + public PfNonTimestampKeyFilter() { + setNameFilter(NAME_FILTER); + setTimeStampStartFilter(TIMESTAMP_START_FILTER); + setTimeStampEndFilter(TIMESTAMP_END_FILTER); + setTimeStampFilter(TIMESTAMP_FILTER); + setNameParameter(NAME_PARAMETER); + } +} diff --git a/models-dao/src/main/java/org/onap/policy/models/dao/impl/PfReferenceTimestampKeyFilter.java b/models-dao/src/main/java/org/onap/policy/models/dao/impl/PfReferenceTimestampKeyFilter.java new file mode 100644 index 000000000..53802f306 --- /dev/null +++ b/models-dao/src/main/java/org/onap/policy/models/dao/impl/PfReferenceTimestampKeyFilter.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.models.dao.impl; + +import org.onap.policy.models.dao.PfFilter; + +/** + * This class is used to set the values for a reference timeStamp key query. + * + */ +public class PfReferenceTimestampKeyFilter extends PfFilter { + private static final String PARENT_NAME_REF_FILTER = "c.key.referenceKey.parentKeyName = :parentKeyName"; + private static final String TIMESTAMP_START_FILTER = "c.key.timeStamp >= :startTime"; + private static final String TIMESTAMP_END_FILTER = "c.key.timeStamp <= :endTime"; + private static final String TIMESTAMP_FILTER = " c.key.timeStamp "; + private static final String NAME_PARAMETER = "parentKeyName"; + + /** + * The default constructor injects query strings. + */ + public PfReferenceTimestampKeyFilter() { + setNameFilter(PARENT_NAME_REF_FILTER); + setTimeStampStartFilter(TIMESTAMP_START_FILTER); + setTimeStampEndFilter(TIMESTAMP_END_FILTER); + setTimeStampFilter(TIMESTAMP_FILTER); + setNameParameter(NAME_PARAMETER); + } +} diff --git a/models-dao/src/main/java/org/onap/policy/models/dao/impl/PfTimestampKeyFilter.java b/models-dao/src/main/java/org/onap/policy/models/dao/impl/PfTimestampKeyFilter.java new file mode 100644 index 000000000..f01f80498 --- /dev/null +++ b/models-dao/src/main/java/org/onap/policy/models/dao/impl/PfTimestampKeyFilter.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.models.dao.impl; + +import org.onap.policy.models.dao.PfFilter; + +/** + * This class is used to set the values for a timeStamp key query. + * + */ +public class PfTimestampKeyFilter extends PfFilter { + private static final String NAME_FILTER = "c.key.name = :name"; + private static final String TIMESTAMP_START_FILTER = "c.key.timeStamp >= :startTime"; + private static final String TIMESTAMP_END_FILTER = "c.key.timeStamp <= :endTime"; + private static final String TIMESTAMP_FILTER = " c.key.timeStamp "; + private static final String NAME_PARAMETER = "name"; + + /** + * The default constructor injects query strings. + */ + public PfTimestampKeyFilter() { + setNameFilter(NAME_FILTER); + setTimeStampStartFilter(TIMESTAMP_START_FILTER); + setTimeStampEndFilter(TIMESTAMP_END_FILTER); + setTimeStampFilter(TIMESTAMP_FILTER); + setNameParameter(NAME_PARAMETER); + } +} diff --git a/models-dao/src/test/java/org/onap/policy/models/dao/DummyGeneratedIdEntity.java b/models-dao/src/test/java/org/onap/policy/models/dao/DummyGeneratedIdEntity.java new file mode 100644 index 000000000..6ba045c54 --- /dev/null +++ b/models-dao/src/test/java/org/onap/policy/models/dao/DummyGeneratedIdEntity.java @@ -0,0 +1,132 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.models.dao; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import javax.persistence.Column; +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NonNull; +import org.onap.policy.common.parameters.BeanValidationResult; +import org.onap.policy.models.base.PfConcept; +import org.onap.policy.models.base.PfGeneratedIdKey; +import org.onap.policy.models.base.PfKey; + + +@Entity +@Table(name = "DummyGeneratedIdEntity") +@Data +@EqualsAndHashCode(callSuper = false) +public class DummyGeneratedIdEntity extends PfConcept { + private static final long serialVersionUID = -2962570563281067896L; + + @EmbeddedId() + @NonNull + private PfGeneratedIdKey key; + + @Column(precision = 3) + @Temporal(TemporalType.TIMESTAMP) + private Date timeStamp; + + @Column + private double doubleValue; + + /** + * Default constructor. + */ + public DummyGeneratedIdEntity() { + this.key = new PfGeneratedIdKey(); + this.timeStamp = new Date(); + } + + public DummyGeneratedIdEntity(DummyGeneratedIdEntity source) { + this.key = source.key; + this.timeStamp = source.timeStamp; + } + + /** + * Constructor. + * + * @param key the key + * @param timeStamp the date value + */ + public DummyGeneratedIdEntity(final PfGeneratedIdKey key, final Date timeStamp) { + this.key = key; + this.timeStamp = timeStamp; + } + + /** + * Constructor. + * + * @param key the key + * @param timeStamp the date value + * @param doubleValue the double value * + */ + public DummyGeneratedIdEntity(final PfGeneratedIdKey key, final Date timeStamp, final double doubleValue) { + this.key = key; + this.timeStamp = timeStamp; + this.doubleValue = doubleValue; + } + + @Override + public List<PfKey> getKeys() { + final List<PfKey> keyList = new ArrayList<>(); + keyList.add(getKey()); + return keyList; + } + + @Override + public BeanValidationResult validate(@NonNull String fieldName) { + BeanValidationResult result = new BeanValidationResult(fieldName, this); + result.addResult(key.validate("key")); + return result; + } + + @Override + public void clean() { + key.clean(); + } + + @Override + public int compareTo(@NonNull final PfConcept otherObj) { + if (this == otherObj) { + return 0; + } + + if (getClass() != otherObj.getClass()) { + return this.getClass().getName().compareTo(otherObj.getClass().getName()); + } + + final DummyGeneratedIdEntity other = (DummyGeneratedIdEntity) otherObj; + if (this.timeStamp != other.timeStamp) { + return timeStamp.compareTo(other.timeStamp); + } + return Double.compare(doubleValue, other.doubleValue); + } + +} diff --git a/models-dao/src/test/java/org/onap/policy/models/dao/EntityTest.java b/models-dao/src/test/java/org/onap/policy/models/dao/EntityTest.java index bc022be0a..80730743b 100644 --- a/models-dao/src/test/java/org/onap/policy/models/dao/EntityTest.java +++ b/models-dao/src/test/java/org/onap/policy/models/dao/EntityTest.java @@ -29,6 +29,7 @@ import static org.junit.Assert.assertNull; import java.time.Instant; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -40,6 +41,7 @@ import org.eclipse.persistence.config.PersistenceUnitProperties; import org.junit.After; import org.junit.Test; import org.onap.policy.models.base.PfConceptKey; +import org.onap.policy.models.base.PfGeneratedIdKey; import org.onap.policy.models.base.PfModelException; import org.onap.policy.models.base.PfReferenceKey; import org.onap.policy.models.base.PfTimestampKey; @@ -62,6 +64,10 @@ public class EntityTest { private static final Instant TIMESTAMP0 = Instant.ofEpochSecond(1613494293); private static final Instant TIMESTAMP1 = Instant.ofEpochSecond(1613494293).plusSeconds(55); private static final Instant TIMESTAMP2 = Instant.ofEpochSecond(1613494293).plusSeconds(90); + private static final Long GENERATEDID0 = 10000L; + private static final Long GENERATEDID1 = 10001L; + private static final Long GENERATEDID2 = 10002L; + private PfDao pfDao; /** @@ -126,9 +132,13 @@ public class EntityTest { testAllOps(); + testGeneratedId(); + testVersionOps(); testgetFilteredOps(); + + testgetFilteredOps2(); } @Test @@ -367,6 +377,111 @@ public class EntityTest { assertEquals(0, pfDao.size(DummyTimestampEntity.class)); } + private void testGeneratedId() { + final PfGeneratedIdKey agKey0 = new PfGeneratedIdKey("AT-KEY0", VERSION001, GENERATEDID0); + final PfGeneratedIdKey agKey1 = new PfGeneratedIdKey("AT-KEY1", VERSION001, GENERATEDID1); + final PfGeneratedIdKey agKey2 = new PfGeneratedIdKey("AT-KEY2", VERSION001, GENERATEDID2); + final DummyGeneratedIdEntity gkeyInfo0 = new DummyGeneratedIdEntity(agKey0, Date.from(TIMESTAMP0)); + final DummyGeneratedIdEntity gkeyInfo1 = new DummyGeneratedIdEntity(agKey1, Date.from(TIMESTAMP1)); + final DummyGeneratedIdEntity gkeyInfo2 = new DummyGeneratedIdEntity(agKey2, Date.from(TIMESTAMP2)); + + pfDao.create(gkeyInfo0); + + final DummyGeneratedIdEntity gkeyInfoBack0 = pfDao.get(DummyGeneratedIdEntity.class, agKey0); + assertEquals(gkeyInfo0, gkeyInfoBack0); + + assertEquals(1, pfDao.getByTimestamp(DummyGeneratedIdEntity.class, agKey0, TIMESTAMP0).size()); + + final DummyGeneratedIdEntity gkeyInfoBackNull = + pfDao.get(DummyGeneratedIdEntity.class, PfGeneratedIdKey.getNullKey()); + assertNull(gkeyInfoBackNull); + + final Set<DummyGeneratedIdEntity> gkeyInfoSetIn = new TreeSet<>(); + gkeyInfoSetIn.add(gkeyInfo1); + gkeyInfoSetIn.add(gkeyInfo2); + + pfDao.createCollection(gkeyInfoSetIn); + + Set<DummyGeneratedIdEntity> gkeyInfoSetOut = new TreeSet<>(pfDao.getAll(DummyGeneratedIdEntity.class)); + + gkeyInfoSetIn.add(gkeyInfo0); + assertEquals(gkeyInfoSetIn, gkeyInfoSetOut); + + pfDao.delete(gkeyInfo1); + gkeyInfoSetIn.remove(gkeyInfo1); + gkeyInfoSetOut = new TreeSet<>(pfDao.getAll(DummyGeneratedIdEntity.class)); + assertEquals(gkeyInfoSetIn, gkeyInfoSetOut); + + pfDao.deleteCollection(gkeyInfoSetIn); + gkeyInfoSetOut = new TreeSet<>(pfDao.getAll(DummyGeneratedIdEntity.class)); + assertEquals(0, gkeyInfoSetOut.size()); + + gkeyInfoSetIn.add(gkeyInfo2); + pfDao.createCollection(gkeyInfoSetIn); + gkeyInfoSetOut = new TreeSet<>(pfDao.getAll(DummyGeneratedIdEntity.class)); + assertEquals(gkeyInfoSetIn, gkeyInfoSetOut); + + pfDao.delete(DummyGeneratedIdEntity.class, agKey2); + gkeyInfoSetOut = new TreeSet<>(pfDao.getAll(DummyGeneratedIdEntity.class)); + assertEquals(gkeyInfoSetOut.size(), pfDao.size(DummyGeneratedIdEntity.class)); + + pfDao.deleteAll(DummyGeneratedIdEntity.class); + assertEquals(0, pfDao.size(DummyGeneratedIdEntity.class)); + + final PfGeneratedIdKey agKey3 = new PfGeneratedIdKey("AT-KEY0", VERSION001); + final PfGeneratedIdKey agKey4 = new PfGeneratedIdKey("AT-KEY1", VERSION001); + final PfGeneratedIdKey agKey5 = new PfGeneratedIdKey("AT-KEY2", VERSION001); + final DummyGeneratedIdEntity gkeyInfo3 = new DummyGeneratedIdEntity(agKey3, Date.from(TIMESTAMP0)); + final DummyGeneratedIdEntity gkeyInfo4 = new DummyGeneratedIdEntity(agKey4, Date.from(TIMESTAMP1)); + final DummyGeneratedIdEntity gkeyInfo5 = new DummyGeneratedIdEntity(agKey5, Date.from(TIMESTAMP2)); + + pfDao.create(gkeyInfo3); + + final DummyGeneratedIdEntity gkeyInfoBack3 = pfDao.get(DummyGeneratedIdEntity.class, agKey3); + assertEquals(gkeyInfo3, gkeyInfoBack3); + + assertEquals(1, pfDao.getByTimestamp(DummyGeneratedIdEntity.class, agKey3, TIMESTAMP0).size()); + + assertEquals(1, gkeyInfo3.getKeys().size()); + + assertEquals(1, gkeyInfo4.compareTo(gkeyInfo3)); + + assertNull(gkeyInfo4.validate(VERSION002).getResult()); + + + gkeyInfoSetIn.clear(); + gkeyInfoSetIn.add(gkeyInfo4); + gkeyInfoSetIn.add(gkeyInfo5); + + pfDao.createCollection(gkeyInfoSetIn); + + gkeyInfoSetOut = new TreeSet<>(pfDao.getAll(DummyGeneratedIdEntity.class)); + + gkeyInfoSetIn.add(gkeyInfo3); + assertEquals(gkeyInfoSetIn, gkeyInfoSetOut); + + pfDao.delete(gkeyInfo4); + gkeyInfoSetIn.remove(gkeyInfo4); + gkeyInfoSetOut = new TreeSet<>(pfDao.getAll(DummyGeneratedIdEntity.class)); + assertEquals(gkeyInfoSetIn, gkeyInfoSetOut); + + pfDao.deleteCollection(gkeyInfoSetIn); + gkeyInfoSetOut = new TreeSet<>(pfDao.getAll(DummyGeneratedIdEntity.class)); + assertEquals(0, gkeyInfoSetOut.size()); + + gkeyInfoSetIn.add(gkeyInfo5); + pfDao.createCollection(gkeyInfoSetIn); + gkeyInfoSetOut = new TreeSet<>(pfDao.getAll(DummyGeneratedIdEntity.class)); + assertEquals(gkeyInfoSetIn, gkeyInfoSetOut); + + pfDao.delete(DummyGeneratedIdEntity.class, agKey5); + gkeyInfoSetOut = new TreeSet<>(pfDao.getAll(DummyGeneratedIdEntity.class)); + assertEquals(gkeyInfoSetOut.size(), pfDao.size(DummyGeneratedIdEntity.class)); + + pfDao.deleteAll(DummyGeneratedIdEntity.class); + assertEquals(0, pfDao.size(DummyGeneratedIdEntity.class)); + } + private void testVersionOps() { final PfConceptKey aKey0 = new PfConceptKey("AAA0", VERSION001); final PfConceptKey aKey1 = new PfConceptKey("AAA0", VERSION002); @@ -466,6 +581,46 @@ public class EntityTest { filterMap.put("doubleValue", 200.1); assertEquals(1, pfDao.getFiltered(DummyTimestampEntity.class, null, null, null, null, filterMap, "DESC", 0).size()); + } + + private void testgetFilteredOps2() { + Map<String, Object> filterMap = new HashMap<>(); + filterMap.put("doubleValue", 200.1); + + final PfGeneratedIdKey agKey0 = new PfGeneratedIdKey("AT-KEY0", VERSION001); + final PfGeneratedIdKey agKey1 = new PfGeneratedIdKey("AT-KEY1", VERSION001); + final PfGeneratedIdKey agKey2 = new PfGeneratedIdKey("AT-KEY2", VERSION001); + final DummyGeneratedIdEntity gkeyInfo0 = new DummyGeneratedIdEntity(agKey0, Date.from(TIMESTAMP0), 200.0); + final DummyGeneratedIdEntity gkeyInfo1 = new DummyGeneratedIdEntity(agKey1, Date.from(TIMESTAMP1), 200.1); + final DummyGeneratedIdEntity gkeyInfo2 = new DummyGeneratedIdEntity(agKey2, Date.from(TIMESTAMP2), 200.2); + + pfDao.create(gkeyInfo0); + pfDao.create(gkeyInfo1); + pfDao.create(gkeyInfo2); + + assertEquals(1, pfDao + .getFiltered(DummyGeneratedIdEntity.class, "AT-KEY0", VERSION001, null, null, null, "DESC", 0).size()); + assertEquals(1, + pfDao.getFiltered(DummyGeneratedIdEntity.class, "AT-KEY0", null, null, null, null, "DESC", 0).size()); + assertEquals(3, pfDao + .getFiltered(DummyGeneratedIdEntity.class, null, VERSION001, TIMESTAMP0, TIMESTAMP2, null, "DESC", 0) + .size()); + assertEquals(1, pfDao + .getFiltered(DummyGeneratedIdEntity.class, "AT-KEY0", VERSION001, + TIMESTAMP0, TIMESTAMP2, null, "DESC", 0) + .size()); + assertEquals(3, pfDao + .getFiltered(DummyGeneratedIdEntity.class, null, VERSION001, null, TIMESTAMP2, null, "DESC", 0).size()); + assertEquals(3, pfDao + .getFiltered(DummyGeneratedIdEntity.class, null, VERSION001, + TIMESTAMP0, null, null, "DESC", 0).size()); + assertEquals(2, + pfDao.getFiltered(DummyGeneratedIdEntity.class, null, VERSION001, + TIMESTAMP0, TIMESTAMP2, null, "DESC", 2) + .size()); + + assertEquals(1, + pfDao.getFiltered(DummyGeneratedIdEntity.class, null, null, null, null, filterMap, "DESC", 0).size()); } } diff --git a/models-dao/src/test/resources/META-INF/persistence.xml b/models-dao/src/test/resources/META-INF/persistence.xml index 3d1f4ff27..fca31e2c6 100644 --- a/models-dao/src/test/resources/META-INF/persistence.xml +++ b/models-dao/src/test/resources/META-INF/persistence.xml @@ -29,6 +29,7 @@ <class>org.onap.policy.models.dao.DummyConceptEntity</class> <class>org.onap.policy.models.dao.DummyReferenceEntity</class> <class>org.onap.policy.models.dao.DummyTimestampEntity</class> + <class>org.onap.policy.models.dao.DummyGeneratedIdEntity</class> <properties> <property name="eclipselink.target-database" value="MySQL" /> diff --git a/models-pdp/src/main/java/org/onap/policy/models/pdp/concepts/PdpStatistics.java b/models-pdp/src/main/java/org/onap/policy/models/pdp/concepts/PdpStatistics.java index f7a0e7d91..c9c4cda0e 100644 --- a/models-pdp/src/main/java/org/onap/policy/models/pdp/concepts/PdpStatistics.java +++ b/models-pdp/src/main/java/org/onap/policy/models/pdp/concepts/PdpStatistics.java @@ -1,8 +1,7 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2019 Nordix Foundation. + * Copyright (C) 2019-2021 Nordix Foundation. * Modifications Copyright (C) 2019 AT&T Intellectual Property. - * Modifications Copyright (C) 2020-2021 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +21,7 @@ package org.onap.policy.models.pdp.concepts; + import java.time.Instant; import java.util.List; import lombok.Data; @@ -40,6 +40,7 @@ public class PdpStatistics { private String pdpInstanceId; private Instant timeStamp; + private Long generatedId; private String pdpGroupName; private String pdpSubGroupName; private long policyDeployCount; @@ -58,6 +59,7 @@ public class PdpStatistics { public PdpStatistics(@NonNull PdpStatistics source) { this.pdpInstanceId = source.pdpInstanceId; this.timeStamp = source.timeStamp; + this.generatedId = source.generatedId; this.pdpGroupName = source.pdpGroupName; this.pdpSubGroupName = source.pdpSubGroupName; this.policyDeployCount = source.policyDeployCount; @@ -68,5 +70,4 @@ public class PdpStatistics { this.policyExecutedSuccessCount = source.policyExecutedSuccessCount; this.engineStats = PfUtils.mapList(source.engineStats, PdpEngineWorkerStatistics::new, null); } - } diff --git a/models-pdp/src/main/java/org/onap/policy/models/pdp/persistence/concepts/JpaPdpStatistics.java b/models-pdp/src/main/java/org/onap/policy/models/pdp/persistence/concepts/JpaPdpStatistics.java index c3329cfa4..ae859325d 100644 --- a/models-pdp/src/main/java/org/onap/policy/models/pdp/persistence/concepts/JpaPdpStatistics.java +++ b/models-pdp/src/main/java/org/onap/policy/models/pdp/persistence/concepts/JpaPdpStatistics.java @@ -25,6 +25,7 @@ package org.onap.policy.models.pdp.persistence.concepts; import java.io.Serializable; import java.time.Instant; +import java.util.Date; import java.util.List; import javax.persistence.Column; import javax.persistence.ElementCollection; @@ -33,16 +34,19 @@ import javax.persistence.Entity; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NonNull; import org.apache.commons.lang3.builder.CompareToBuilder; +import org.eclipse.persistence.annotations.Index; import org.onap.policy.common.parameters.annotations.NotNull; import org.onap.policy.models.base.PfAuthorative; import org.onap.policy.models.base.PfConcept; +import org.onap.policy.models.base.PfGeneratedIdKey; import org.onap.policy.models.base.PfKey; -import org.onap.policy.models.base.PfTimestampKey; import org.onap.policy.models.base.PfUtils; import org.onap.policy.models.base.validation.annotations.VerifyKey; import org.onap.policy.models.pdp.concepts.PdpEngineWorkerStatistics; @@ -55,6 +59,7 @@ import org.onap.policy.models.pdp.concepts.PdpStatistics; */ @Entity @Table(name = "PdpStatistics") +@Index(name = "IDX_TSIDX1", columnNames = {"timeStamp", "name", "version"}) @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) @Data @AllArgsConstructor @@ -66,7 +71,11 @@ public class JpaPdpStatistics extends PfConcept implements PfAuthorative<PdpStat @EmbeddedId @VerifyKey @NotNull - private PfTimestampKey key; + private PfGeneratedIdKey key; + + @Column(precision = 3) + @Temporal(TemporalType.TIMESTAMP) + private Date timeStamp; @Column(length = 120) private String pdpGroupName; @@ -99,7 +108,7 @@ public class JpaPdpStatistics extends PfConcept implements PfAuthorative<PdpStat * The Default Constructor creates a {@link JpaPdpStatistics} object with a null key. */ public JpaPdpStatistics() { - this(new PfTimestampKey()); + this(new PfGeneratedIdKey()); } /** @@ -107,11 +116,10 @@ public class JpaPdpStatistics extends PfConcept implements PfAuthorative<PdpStat * * @param key the key */ - public JpaPdpStatistics(@NonNull final PfTimestampKey key) { - this(key, NULL_NAME, NULL_NAME, 0L, 0L, 0L, 0L, 0L, 0L, null); + public JpaPdpStatistics(@NonNull final PfGeneratedIdKey key) { + this(key, null, NULL_NAME, NULL_NAME, 0L, 0L, 0L, 0L, 0L, 0L, null); } - /** * Copy constructor. * @@ -119,7 +127,8 @@ public class JpaPdpStatistics extends PfConcept implements PfAuthorative<PdpStat */ public JpaPdpStatistics(@NonNull final JpaPdpStatistics copyConcept) { super(copyConcept); - this.key = new PfTimestampKey(copyConcept.key); + this.key = new PfGeneratedIdKey(copyConcept.key); + this.timeStamp = copyConcept.timeStamp; this.pdpGroupName = copyConcept.pdpGroupName; this.pdpSubGroupName = copyConcept.pdpSubGroupName; this.policyDeployCount = copyConcept.policyDeployCount; @@ -153,7 +162,10 @@ public class JpaPdpStatistics extends PfConcept implements PfAuthorative<PdpStat } final JpaPdpStatistics other = (JpaPdpStatistics) otherConcept; - return new CompareToBuilder().append(this.key, other.key).append(this.pdpGroupName, other.pdpGroupName) + return new CompareToBuilder() + .append(this.key, other.key) + .append(this.timeStamp, other.timeStamp) + .append(this.pdpGroupName, other.pdpGroupName) .append(this.pdpSubGroupName, other.pdpSubGroupName) .append(this.policyDeployCount, other.policyDeployCount) .append(this.policyDeployFailCount, other.policyDeployFailCount) @@ -167,7 +179,8 @@ public class JpaPdpStatistics extends PfConcept implements PfAuthorative<PdpStat public PdpStatistics toAuthorative() { PdpStatistics pdpStatistics = new PdpStatistics(); pdpStatistics.setPdpInstanceId(key.getName()); - pdpStatistics.setTimeStamp(key.getInstant()); + pdpStatistics.setGeneratedId(key.getGeneratedId()); + pdpStatistics.setTimeStamp(timeStamp.toInstant()); pdpStatistics.setPdpGroupName(pdpGroupName); pdpStatistics.setPdpSubGroupName(pdpSubGroupName); pdpStatistics.setPolicyDeployCount(policyDeployCount); @@ -183,9 +196,16 @@ public class JpaPdpStatistics extends PfConcept implements PfAuthorative<PdpStat @Override public void fromAuthorative(@NonNull final PdpStatistics pdpStatistics) { - if (this.key == null || this.getKey().isNullKey()) { - this.setKey(new PfTimestampKey(pdpStatistics.getPdpInstanceId(), PfKey.NULL_KEY_VERSION, - pdpStatistics.getTimeStamp() == null ? Instant.EPOCH : pdpStatistics.getTimeStamp())); + if (pdpStatistics.getGeneratedId() == null) { + this.setKey(new PfGeneratedIdKey(pdpStatistics.getPdpInstanceId(), PfKey.NULL_KEY_VERSION)); + } else { + this.setKey(new PfGeneratedIdKey(pdpStatistics.getPdpInstanceId(), + PfKey.NULL_KEY_VERSION, pdpStatistics.getGeneratedId())); + } + if (pdpStatistics.getTimeStamp() == null) { + this.setTimeStamp(Date.from(Instant.EPOCH)); + } else { + this.setTimeStamp(Date.from(pdpStatistics.getTimeStamp())); } this.setPdpGroupName(pdpStatistics.getPdpGroupName()); this.setPdpSubGroupName(pdpStatistics.getPdpSubGroupName()); diff --git a/models-pdp/src/main/java/org/onap/policy/models/pdp/persistence/provider/PdpStatisticsProvider.java b/models-pdp/src/main/java/org/onap/policy/models/pdp/persistence/provider/PdpStatisticsProvider.java index e030d089d..ece09b088 100644 --- a/models-pdp/src/main/java/org/onap/policy/models/pdp/persistence/provider/PdpStatisticsProvider.java +++ b/models-pdp/src/main/java/org/onap/policy/models/pdp/persistence/provider/PdpStatisticsProvider.java @@ -32,10 +32,10 @@ import java.util.stream.Collectors; import javax.ws.rs.core.Response; import lombok.NonNull; import org.onap.policy.common.parameters.BeanValidationResult; +import org.onap.policy.models.base.PfGeneratedIdKey; import org.onap.policy.models.base.PfKey; import org.onap.policy.models.base.PfModelException; import org.onap.policy.models.base.PfModelRuntimeException; -import org.onap.policy.models.base.PfTimestampKey; import org.onap.policy.models.dao.PfDao; import org.onap.policy.models.pdp.concepts.PdpStatistics; import org.onap.policy.models.pdp.persistence.concepts.JpaPdpStatistics; @@ -58,13 +58,32 @@ public class PdpStatisticsProvider { * @return the PDP statistics found * @throws PfModelException on errors getting PDP statistics */ - public List<PdpStatistics> getPdpStatistics(@NonNull final PfDao dao, final String name, final Instant timestamp) + public List<PdpStatistics> getPdpStatistics(@NonNull final PfDao dao, final String name, final Instant timeStamp) + throws PfModelException { + List<PdpStatistics> pdpStatistics = new ArrayList<>(); + if (name != null && timeStamp != null) { + return asPdpStatisticsList(dao.getByTimestamp(JpaPdpStatistics.class, + new PfGeneratedIdKey(name, PfKey.NULL_KEY_VERSION), timeStamp)); + } else { + return asPdpStatisticsList(dao.getAll(JpaPdpStatistics.class)); + } + } + + /** + * Get PDP statistics. + * + * @param dao the DAO to use to access the database + * @param name the name of the PDP statistics to get, null to get all PDPs + * @return the PDP statistics found + * @throws PfModelException on errors getting PDP statistics + */ + public List<PdpStatistics> getPdpStatistics(@NonNull final PfDao dao, final String name) throws PfModelException { List<PdpStatistics> pdpStatistics = new ArrayList<>(); if (name != null) { pdpStatistics - .add(dao.get(JpaPdpStatistics.class, new PfTimestampKey(name, PfKey.NULL_KEY_VERSION, timestamp)) + .add(dao.get(JpaPdpStatistics.class, new PfGeneratedIdKey(name, PfKey.NULL_KEY_VERSION)) .toAuthorative()); } else { return asPdpStatisticsList(dao.getAll(JpaPdpStatistics.class)); @@ -95,7 +114,8 @@ public class PdpStatisticsProvider { filterMap.put("pdpSubGroupName", pdpSubGroup); } - return asPdpStatisticsList(dao.getFiltered(JpaPdpStatistics.class, name, PfKey.NULL_KEY_VERSION, startTimeStamp, + return asPdpStatisticsList(dao.getFiltered(JpaPdpStatistics.class, name, + PfKey.NULL_KEY_VERSION, startTimeStamp, endTimeStamp, filterMap, sortOrder, getRecordNum)); } @@ -109,17 +129,16 @@ public class PdpStatisticsProvider { */ public List<PdpStatistics> createPdpStatistics(@NonNull final PfDao dao, @NonNull final List<PdpStatistics> pdpStatisticsList) throws PfModelException { - for (PdpStatistics pdpStatistics : pdpStatisticsList) { JpaPdpStatistics jpaPdpStatistics = new JpaPdpStatistics(); jpaPdpStatistics.fromAuthorative(pdpStatistics); - BeanValidationResult validationResult = jpaPdpStatistics.validate("pdp statistics"); if (!validationResult.isValid()) { throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult()); } dao.create(jpaPdpStatistics); + pdpStatistics.setGeneratedId(jpaPdpStatistics.getKey().getGeneratedId()); } // Return the created PDP statistics @@ -127,11 +146,10 @@ public class PdpStatisticsProvider { for (PdpStatistics pdpStatisticsItem : pdpStatisticsList) { JpaPdpStatistics jpaPdpStatistics = - dao.get(JpaPdpStatistics.class, new PfTimestampKey(pdpStatisticsItem.getPdpInstanceId(), - PfKey.NULL_KEY_VERSION, pdpStatisticsItem.getTimeStamp())); + dao.get(JpaPdpStatistics.class, new PfGeneratedIdKey(pdpStatisticsItem.getPdpInstanceId(), + PfKey.NULL_KEY_VERSION, pdpStatisticsItem.getGeneratedId())); pdpStatistics.add(jpaPdpStatistics.toAuthorative()); } - return pdpStatistics; } @@ -163,8 +181,8 @@ public class PdpStatisticsProvider { for (PdpStatistics pdpStatisticsItem : pdpStatisticsList) { JpaPdpStatistics jpaPdpStatistics = - dao.get(JpaPdpStatistics.class, new PfTimestampKey(pdpStatisticsItem.getPdpInstanceId(), - PfKey.NULL_KEY_VERSION, pdpStatisticsItem.getTimeStamp())); + dao.get(JpaPdpStatistics.class, new PfGeneratedIdKey(pdpStatisticsItem.getPdpInstanceId(), + PfKey.NULL_KEY_VERSION, pdpStatisticsItem.getGeneratedId())); pdpStatistics.add(jpaPdpStatistics.toAuthorative()); } @@ -182,11 +200,12 @@ public class PdpStatisticsProvider { */ public List<PdpStatistics> deletePdpStatistics(@NonNull final PfDao dao, @NonNull final String name, final Instant timestamp) { - List<PdpStatistics> pdpStatisticsListToDel = asPdpStatisticsList(dao.getFiltered(JpaPdpStatistics.class, name, + List<PdpStatistics> pdpStatisticsListToDel = asPdpStatisticsList( + dao.getFiltered(JpaPdpStatistics.class, name, PfKey.NULL_KEY_VERSION, timestamp, timestamp, null, DESC_ORDER, 0)); pdpStatisticsListToDel.stream().forEach(s -> dao.delete(JpaPdpStatistics.class, - new PfTimestampKey(s.getPdpInstanceId(), PfKey.NULL_KEY_VERSION, s.getTimeStamp()))); + new PfGeneratedIdKey(s.getPdpInstanceId(), PfKey.NULL_KEY_VERSION, s.getGeneratedId()))); return pdpStatisticsListToDel; } diff --git a/models-pdp/src/test/java/org/onap/policy/models/pdp/persistence/concepts/JpaPdpStatisticsTest.java b/models-pdp/src/test/java/org/onap/policy/models/pdp/persistence/concepts/JpaPdpStatisticsTest.java index 405425e2c..819c3b6e7 100644 --- a/models-pdp/src/test/java/org/onap/policy/models/pdp/persistence/concepts/JpaPdpStatisticsTest.java +++ b/models-pdp/src/test/java/org/onap/policy/models/pdp/persistence/concepts/JpaPdpStatisticsTest.java @@ -31,7 +31,7 @@ import static org.junit.Assert.assertTrue; import java.time.Instant; import java.util.ArrayList; import org.junit.Test; -import org.onap.policy.models.base.PfTimestampKey; +import org.onap.policy.models.base.PfGeneratedIdKey; import org.onap.policy.models.pdp.concepts.PdpStatistics; /** @@ -41,14 +41,14 @@ public class JpaPdpStatisticsTest { @Test public void testConstructor() { - assertThatThrownBy(() -> new JpaPdpStatistics((PfTimestampKey) null)).hasMessageContaining("key"); + assertThatThrownBy(() -> new JpaPdpStatistics((PfGeneratedIdKey) null)).hasMessageContaining("key"); assertThatThrownBy(() -> new JpaPdpStatistics((JpaPdpStatistics) null)).hasMessageContaining("copyConcept"); assertThatThrownBy(() -> new JpaPdpStatistics((PdpStatistics) null)).hasMessageContaining("authorativeConcept"); assertNotNull(new JpaPdpStatistics()); - assertNotNull(new JpaPdpStatistics(new PfTimestampKey())); + assertNotNull(new JpaPdpStatistics(new PfGeneratedIdKey())); PdpStatistics pdpStat = createPdpStatistics(); JpaPdpStatistics jpaPdpStat = new JpaPdpStatistics(createPdpStatistics()); @@ -114,7 +114,7 @@ public class JpaPdpStatisticsTest { assertEquals(pdpStat.getPdpInstanceId(), jpaPdpStat.getKey().getName()); assertEquals(pdpStat.getPdpGroupName(), jpaPdpStat.getPdpGroupName()); assertEquals(pdpStat.getPdpSubGroupName(), jpaPdpStat.getPdpSubGroupName()); - assertEquals(pdpStat.getTimeStamp(), jpaPdpStat.getKey().getInstant()); + assertEquals(pdpStat.getTimeStamp(), jpaPdpStat.getTimeStamp().toInstant()); assertEquals(pdpStat.getPolicyDeployCount(), jpaPdpStat.getPolicyDeployCount()); assertEquals(pdpStat.getPolicyDeploySuccessCount(), jpaPdpStat.getPolicyDeploySuccessCount()); assertEquals(pdpStat.getPolicyDeployFailCount(), jpaPdpStat.getPolicyDeployFailCount()); @@ -128,6 +128,7 @@ public class JpaPdpStatisticsTest { pdpStat.setPdpInstanceId("PDP0"); pdpStat.setPdpGroupName("PDPGroup0"); pdpStat.setPdpSubGroupName("PDPSubGroup0"); + pdpStat.setGeneratedId(10001L); pdpStat.setTimeStamp(Instant.EPOCH); pdpStat.setPolicyDeployCount(3); pdpStat.setPolicyDeploySuccessCount(1); diff --git a/models-pdp/src/test/java/org/onap/policy/models/pdp/persistence/provider/PdpStatisticsProviderTest.java b/models-pdp/src/test/java/org/onap/policy/models/pdp/persistence/provider/PdpStatisticsProviderTest.java index b8d33150d..8259dc0c6 100644 --- a/models-pdp/src/test/java/org/onap/policy/models/pdp/persistence/provider/PdpStatisticsProviderTest.java +++ b/models-pdp/src/test/java/org/onap/policy/models/pdp/persistence/provider/PdpStatisticsProviderTest.java @@ -50,6 +50,8 @@ public class PdpStatisticsProviderTest { private static final String SUBGROUP = "subgroup"; private static final Instant TIMESTAMP1 = Instant.ofEpochSecond(1078884319); private static final Instant TIMESTAMP2 = Instant.ofEpochSecond(1078884350); + private static final Long GENERATEDID1 = 1L; + private static final Long GENERATEDID2 = 2L; private static final String ORDER = "DESC"; private PfDao pfDao; @@ -90,6 +92,7 @@ public class PdpStatisticsProviderTest { PdpStatistics pdpStatistics = new PdpStatistics(); pdpStatistics.setPdpInstanceId(NAME); pdpStatistics.setTimeStamp(TIMESTAMP1); + pdpStatistics.setGeneratedId(GENERATEDID1); pdpStatistics.setPdpGroupName(GROUP); pdpStatistics.setPdpSubGroupName(SUBGROUP); pdpStatistics.setPolicyDeployCount(2); @@ -105,6 +108,7 @@ public class PdpStatisticsProviderTest { PdpStatistics pdpStatistics2 = new PdpStatistics(); pdpStatistics2.setPdpInstanceId("name2"); pdpStatistics2.setTimeStamp(TIMESTAMP2); + pdpStatistics2.setGeneratedId(GENERATEDID2); pdpStatistics2.setPdpGroupName(GROUP); pdpStatistics2.setPdpSubGroupName(SUBGROUP); pdpStatistics2.setPolicyDeployCount(2); @@ -121,7 +125,6 @@ public class PdpStatisticsProviderTest { createdPdpStatisticsList = new PdpStatisticsProvider().createPdpStatistics(pfDao, pdpStatisticsTestList); createdListStr = createdPdpStatisticsList.toString(); assertEquals(createdListStr.replaceAll("\\s+", ""), testListStr.replaceAll("\\s+", "")); - } @After @@ -219,7 +222,6 @@ public class PdpStatisticsProviderTest { new PdpStatisticsProvider().updatePdpStatistics(pfDao, pdpStatisticsTestList); String gotListStr = updatePdpStatisticsList.toString(); assertEquals(testListStr.replaceAll("\\s+", ""), gotListStr.replaceAll("\\s+", "")); - } @Test |