Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • simonrose/naming-backend
  • anderslindh1/naming-backend
  • andersharrisson/naming-backend
3 results
Show changes
Showing
with 4496 additions and 2466 deletions
/*
* Copyright (C) 2021 European Spallation Source ERIC.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.openepics.names.repository.wip;
import java.util.List;
import org.openepics.names.repository.model.wip.WipSystemGroup;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
/**
* Find system group structure (name part) information in JPA.
*
* @author Lars Johansson
*/
@Repository
public interface IWipSystemGroupRepository extends JpaRepository<WipSystemGroup, Long> {
// old + verification
@Query("FROM WipSystemGroup sg WHERE sg.uuid = ?1")
List<WipSystemGroup> findByUuid(String uuid);
@Query("FROM WipSystemGroup sg WHERE sg.latest = true AND sg.mnemonic = ?1")
List<WipSystemGroup> findLatestByMnemonic(String mnemonic);
// ----------------------------------------------------------------------------------------------------
@Query("FROM WipSystemGroup sg WHERE sg.latest = true AND sg.uuid = ?1")
WipSystemGroup findLatestByUuid(String uuid);
@Query("FROM WipSystemGroup sg WHERE sg.latest = true AND sg.deleted = false AND sg.mnemonic = ?1")
WipSystemGroup findLatestNotDeletedByMnemonic(String mnemonic);
@Query("FROM WipSystemGroup sg WHERE sg.latest = true AND sg.deleted = false AND sg.uuid = ?1")
WipSystemGroup findLatestNotDeletedByUuid(String uuid);
@Query("FROM WipSystemGroup sg WHERE sg.latest = true")
List<WipSystemGroup> findLatest();
@Query("FROM WipSystemGroup sg WHERE sg.latest = true AND sg.deleted = false")
List<WipSystemGroup> findLatestNotDeleted();
@Query("FROM WipSystemGroup sg WHERE sg.uuid = ?1 AND sg.id < ?2 ORDER BY sg.id DESC")
List<WipSystemGroup> findPreviousByUuidAndId(String uuid, Long id);
}
/*
* Copyright (C) 2021 European Spallation Source ERIC.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.openepics.names.repository.wip;
import java.util.List;
import org.openepics.names.repository.model.wip.WipSystem;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
/**
* Find system structure (name part) information in JPA.
*
* @author Lars Johansson
*/
@Repository
public interface IWipSystemRepository extends JpaRepository<WipSystem, Long> {
// old + verification
@Query("FROM WipSystem sys WHERE sys.uuid = ?1")
List<WipSystem> findByUuid(String uuid);
@Query("FROM WipSystem sys WHERE sys.latest = true AND sys.mnemonic = ?1")
List<WipSystem> findLatestByMnemonic(String mnemonic);
// ----------------------------------------------------------------------------------------------------
@Query("FROM WipSystem sys WHERE sys.latest = true AND sys.uuid = ?1")
WipSystem findLatestByUuid(String uuid);
@Query("FROM WipSystem sys WHERE sys.latest = true AND sys.deleted = false AND sys.mnemonic = ?1")
WipSystem findLatestNotDeletedByMnemonic(String mnemonic);
@Query("FROM WipSystem sys WHERE sys.latest = true AND sys.deleted = false AND sys.uuid = ?1")
WipSystem findLatestNotDeletedByUuid(String uuid);
@Query("FROM WipSystem sys WHERE sys.latest = true")
List<WipSystem> findLatest();
@Query("FROM WipSystem sys WHERE sys.latest = true AND sys.deleted = false")
List<WipSystem> findLatestNotDeleted();
@Query("FROM WipSystem sys WHERE sys.latest = true AND sys.deleted = false AND sys.parentUuid = ?1")
List<WipSystem> findLatestNotDeletedByParent(String uuid);
@Query("FROM WipSystem sys WHERE sys.uuid = ?1 AND sys.id < ?2 ORDER BY sys.id DESC")
List<WipSystem> findPreviousByUuidAndId(String uuid, Long id);
}
/*
* Copyright (C) 2021 European Spallation Source ERIC.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.openepics.names.repository.wip;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.openepics.names.repository.model.Persistable;
import org.openepics.names.repository.model.wip.WipDeviceGroup;
import org.openepics.names.repository.model.wip.WipNameStructure;
import org.openepics.names.repository.model.wip.WipStructure;
import org.openepics.names.rest.beans.FieldStructure;
import org.openepics.names.rest.beans.Status;
import org.openepics.names.util.RepositoryUtil;
import org.springframework.stereotype.Repository;
/**
* Handle device group information in JPA.
*
* @author Lars Johansson
*/
@Repository
public class WipDeviceGroupRepository {
@PersistenceContext
private EntityManager em;
/**
* Count device groups.
*
* @param deleted deleted
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param includeHistory include history
* @return count of device groups
*/
public Long countDeviceGroups(Boolean deleted,
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
Boolean includeHistory) {
// note
// use of function for mnemonic path
// where
// deleted
// queryFields, queryValues
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<WipDeviceGroup> from = cq.from(WipDeviceGroup.class);
cq.where(cb.and(preparePredicatesDeviceGroups(cb, cq, from, deleted,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
includeHistory).toArray(new Predicate[0])));
cq.select(cb.count(from));
return em.createQuery(cq).getSingleResult();
}
/**
* Find device groups.
*
* @param deleted deleted
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @return list of device groups
*/
public List<WipDeviceGroup> readDeviceGroups(Boolean deleted,
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who) {
return readDeviceGroups(deleted,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
Boolean.FALSE, null, null, null, null);
}
/**
* Find device groups.
*
* @param deleted deleted
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param includeHistory include history
* @param orderBy order by
* @param isAsc is ascending
* @param offset offset
* @param limit limit
* @return list of device groups
*/
public List<WipDeviceGroup> readDeviceGroups(Boolean deleted,
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
Boolean includeHistory, FieldStructure orderBy, Boolean isAsc, Integer offset, Integer limit) {
// note
// use of function for mnemonic path
// where
// deleted
// queryFields, queryValues
// order
// orderBy, isAsc
// paging
// offset, limit
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<WipDeviceGroup> cq = cb.createQuery(WipDeviceGroup.class);
Root<WipDeviceGroup> from = cq.from(WipDeviceGroup.class);
cq.where(cb.and(preparePredicatesDeviceGroups(cb, cq, from, deleted,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
includeHistory).toArray(new Predicate[0])));
cq.select(from);
if (orderBy != null) {
Expression<String> exp = orderBy(from, orderBy);
if (BooleanUtils.toBoolean(isAsc)) {
cq.orderBy(cb.asc(exp));
} else {
cq.orderBy(cb.desc(exp));
}
}
TypedQuery<WipDeviceGroup> query = em.createQuery(cq);
if (offset != null && limit != null) {
query.setFirstResult(offset * limit);
query.setMaxResults(limit);
}
return query.getResultList();
}
/**
* Prepare predicates for device groups.
*
* @param cb criteria builder
* @param cq criteria query
* @param from criteria query root
* @param deleted deleted
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param includeHistory include history
* @return list of predicates
*/
private List<Predicate> preparePredicatesDeviceGroups(CriteriaBuilder cb, CriteriaQuery cq, Root<WipDeviceGroup> from, Boolean deleted,
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
Boolean includeHistory) {
List<Predicate> predicates = new ArrayList<>();
if (!Boolean.TRUE.equals(includeHistory)) {
// purpose of Naming to show valid entries
// therefore
// exclude some values unless history requested
// make sure to not exclude present and future values (latest approved and pending)
//
// condition(s)
// exclude content (with latest) before latest
// exclude content (with latest) after latest (cancelled, rejected)
// keep most recent content (without latest) (to have most recent in line of uuid without latest)
// <-->
// select * from structure s
// where (
// not (exists (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.id < (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true))
// and not (exists (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.id > (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.status in ('CANCELLED', 'REJECTED'))
// and not (not exists (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.id < (select max(s2.id) from structure s2 where s2."uuid" = s."uuid" and s2.latest=false))
// )
// <-->
// not (exists (subquery id) and s.id < (subquery id))
// and not (exists (subquery id) and s.id > (subquery id) and s.status in ('CANCELLED', 'REJECTED'))
// and not (not exists (subquery id) and s.id < (subquery 2))
//
// note
// persistence libraries may optimize query
// e.g. change (!a and !b) to !(a or b)
Subquery<Long> sub = cq.subquery(Long.class);
Root<WipDeviceGroup> fromSub = sub.from(WipDeviceGroup.class);
sub.where(cb.and(
cb.equal(fromSub.get(WipNameStructure.FIELD_UUID), from.get(WipNameStructure.FIELD_UUID)),
cb.equal(fromSub.get(WipNameStructure.FIELD_LATEST), Boolean.TRUE)
));
sub.select(fromSub.get(Persistable.FIELD_ID));
Subquery<Long> sub2 = cq.subquery(Long.class);
Root<WipDeviceGroup> fromSub2 = sub2.from(WipDeviceGroup.class);
sub2.where(cb.and(
cb.equal(fromSub2.get(WipNameStructure.FIELD_UUID), from.get(WipNameStructure.FIELD_UUID)),
cb.equal(fromSub2.get(WipNameStructure.FIELD_LATEST), Boolean.FALSE)
));
sub2.select(cb.max(fromSub2.get(Persistable.FIELD_ID)));
Predicate predicateExclude =
cb.and(
cb.not(cb.and(
cb.exists(sub),
cb.lessThan(from.get(Persistable.FIELD_ID).as(Long.class), sub))),
cb.not(cb.and(
cb.exists(sub),
cb.greaterThan(from.get(Persistable.FIELD_ID).as(Long.class), sub),
cb.or(
cb.equal(from.get(WipNameStructure.FIELD_STATUS), Status.CANCELLED),
cb.equal(from.get(WipNameStructure.FIELD_STATUS), Status.REJECTED)))),
cb.not(cb.and(
cb.not(cb.exists(sub)),
cb.lessThan(from.get(Persistable.FIELD_ID).as(Long.class), sub2)))
);
predicates.add(predicateExclude);
}
if (deleted != null) {
predicates.add(cb.equal(from.get(WipNameStructure.FIELD_DELETED), deleted));
}
// prepare pattern
// jpa query characters % and _
// remove excess % characters
if (!StringUtils.isEmpty(uuid)) {
predicates.add(cb.and(cb.equal(from.get(WipNameStructure.FIELD_UUID), RepositoryUtil.preparePattern(uuid))));
}
if (!StringUtils.isEmpty(parentUuid)) {
predicates.add(cb.and(cb.equal(from.get(WipDeviceGroup.FIELD_PARENT_UUID), RepositoryUtil.preparePattern(parentUuid))));
}
if (!StringUtils.isEmpty(mnemonic)) {
predicates.add(cb.and(cb.like(from.get(WipStructure.FIELD_MNEMONIC), RepositoryUtil.preparePattern(mnemonic))));
}
if (!StringUtils.isEmpty(mnemonicEquivalence)) {
predicates.add(cb.and(cb.like(from.get(WipStructure.FIELD_MNEMONIC_EQUIVALENCE), RepositoryUtil.preparePattern(mnemonicEquivalence))));
}
if (!StringUtils.isEmpty(mnemonicPath)) {
predicates.add(cb.and(cb.like(cb.function(WipDeviceGroup.FUNCTION_GET_MNEMONIC_PATH_DEVICEGROUP, String.class, from.get(WipNameStructure.FIELD_UUID)), RepositoryUtil.preparePattern(mnemonicPath))));
}
if (!StringUtils.isEmpty(description)) {
predicates.add(cb.and(cb.like(from.get(WipNameStructure.FIELD_DESCRIPTION), RepositoryUtil.preparePattern(description))));
}
if (!StringUtils.isEmpty(who)) {
predicates.add(cb.and(cb.like(from.get(WipNameStructure.FIELD_PROCESSED_BY), RepositoryUtil.preparePattern(who))));
}
return predicates;
}
/**
* Prepare order by query expression.
*
* @param root root type in the from clause
* @param orderBy field on which to order by
* @return order by query expression
*/
private Expression<String> orderBy(Root<WipDeviceGroup> root, FieldStructure orderBy) {
if (FieldStructure.UUID.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_UUID);
} else if (FieldStructure.PARENT.equals(orderBy)) {
return root.get(WipDeviceGroup.FIELD_PARENT_UUID);
} else if (FieldStructure.MNEMONIC.equals(orderBy)) {
return root.get(WipStructure.FIELD_MNEMONIC);
} else if (FieldStructure.MNEMONICPATH.equals(orderBy)) {
return root.get(WipStructure.FIELD_MNEMONIC);
} else if (FieldStructure.ORDERING.equals(orderBy)) {
return root.get(WipStructure.FIELD_ORDERING);
} else if (FieldStructure.DESCRIPTION.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_DESCRIPTION);
} else if (FieldStructure.WHEN.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_PROCESSED);
} else {
return root.get(WipStructure.FIELD_MNEMONIC);
}
}
/**
* Count device groups history.
*
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @return count of device groups
*/
public Long countDeviceGroupsHistory(
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who) {
// note
// use of function for mnemonic path
// deleted - null
// includeHistory - true
// where
// queryFields, queryValues
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<WipDeviceGroup> from = cq.from(WipDeviceGroup.class);
Subquery<String> sub = cq.subquery(String.class);
Root<WipDeviceGroup> fromSub = sub.from(WipDeviceGroup.class);
sub.where(cb.and(preparePredicatesDeviceGroups(cb, cq, fromSub, null,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
Boolean.TRUE).toArray(new Predicate[0])));
sub.select(fromSub.get(WipNameStructure.FIELD_UUID));
cq.where(cb.and(cb.in(from.get(WipNameStructure.FIELD_UUID)).value(sub)));
cq.select(cb.count(from));
return em.createQuery(cq).getSingleResult();
}
/**
* Find device groups history.
*
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param orderBy order by
* @param isAsc is ascending
* @return list of device groups
*/
public List<WipDeviceGroup> readDeviceGroupsHistory(
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
FieldStructure orderBy, Boolean isAsc) {
// note
// use of function for mnemonic path
// deleted - null
// includeHistory - true
// where
// queryFields, queryValues
// order
// orderBy, isAsc
// paging
// outside of method
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<WipDeviceGroup> cq = cb.createQuery(WipDeviceGroup.class);
Root<WipDeviceGroup> from = cq.from(WipDeviceGroup.class);
Subquery<String> sub = cq.subquery(String.class);
Root<WipDeviceGroup> fromSub = sub.from(WipDeviceGroup.class);
sub.where(cb.and(preparePredicatesDeviceGroups(cb, cq, fromSub, null,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
Boolean.TRUE).toArray(new Predicate[0])));
sub.select(fromSub.get(WipNameStructure.FIELD_UUID));
cq.where(cb.and(cb.in(from.get(WipNameStructure.FIELD_UUID)).value(sub)));
cq.select(from);
if (orderBy != null) {
Expression<String> exp = orderBy(from, orderBy);
if (BooleanUtils.toBoolean(isAsc)) {
cq.orderBy(cb.asc(exp));
} else {
cq.orderBy(cb.desc(exp));
}
}
return em.createQuery(cq).getResultList();
}
/**
* Persist device group into persistence context.
*
* @param deviceGroup device group
*/
public void createDeviceGroup(WipDeviceGroup deviceGroup) {
em.persist(deviceGroup);
}
/**
* Merge device group into persistence context.
*
* @param deviceGroup device group
*/
public void updateDeviceGroup(WipDeviceGroup deviceGroup) {
em.merge(deviceGroup);
}
}
/*
* Copyright (C) 2021 European Spallation Source ERIC.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.openepics.names.repository.wip;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.openepics.names.repository.model.Persistable;
import org.openepics.names.repository.model.wip.WipDeviceType;
import org.openepics.names.repository.model.wip.WipNameStructure;
import org.openepics.names.repository.model.wip.WipStructure;
import org.openepics.names.rest.beans.FieldStructure;
import org.openepics.names.rest.beans.Status;
import org.openepics.names.util.RepositoryUtil;
import org.springframework.stereotype.Repository;
/**
* Handle device type information in JPA.
*
* @author Lars Johansson
*/
@Repository
public class WipDeviceTypeRepository {
@PersistenceContext
private EntityManager em;
/**
* Count device types.
*
* @param deleted deleted
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param includeHistory include history
* @return count of device types
*/
public Long countDeviceTypes(Boolean deleted,
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
Boolean includeHistory) {
// note
// use of function for mnemonic path
// where
// deleted
// queryFields, queryValues
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<WipDeviceType> from = cq.from(WipDeviceType.class);
cq.where(cb.and(preparePredicatesDeviceTypes(cb, cq, from, deleted,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
includeHistory).toArray(new Predicate[0])));
cq.select(cb.count(from));
return em.createQuery(cq).getSingleResult();
}
/**
* Find device types.
*
* @param deleted deleted
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @return list of device types
*/
public List<WipDeviceType> readDeviceTypes(Boolean deleted,
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who) {
return readDeviceTypes(deleted,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
Boolean.FALSE, null, null, null, null);
}
/**
* Find device types.
*
* @param deleted deleted
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param includeHistory include history
* @param orderBy order by
* @param isAsc is ascending
* @param offset offset
* @param limit limit
* @return list of device types
*/
public List<WipDeviceType> readDeviceTypes(Boolean deleted,
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
Boolean includeHistory, FieldStructure orderBy, Boolean isAsc, Integer offset, Integer limit) {
// note
// use of function for mnemonic path
// where
// deleted
// queryFields, queryValues
// order
// orderBy, isAsc
// paging
// offset, limit
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<WipDeviceType> cq = cb.createQuery(WipDeviceType.class);
Root<WipDeviceType> from = cq.from(WipDeviceType.class);
cq.where(cb.and(preparePredicatesDeviceTypes(cb, cq, from, deleted,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
includeHistory).toArray(new Predicate[0])));
cq.select(from);
if (orderBy != null) {
Expression<String> exp = orderBy(from, orderBy);
if (BooleanUtils.toBoolean(isAsc)) {
cq.orderBy(cb.asc(exp));
} else {
cq.orderBy(cb.desc(exp));
}
}
TypedQuery<WipDeviceType> query = em.createQuery(cq);
if (offset != null && limit != null) {
query.setFirstResult(offset * limit);
query.setMaxResults(limit);
}
return query.getResultList();
}
/**
* Prepare predicates for device types.
*
* @param cb criteria builder
* @param cq criteria query
* @param from criteria query root
* @param deleted deleted
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param includeHistory include history
* @return list of predicates
*/
private List<Predicate> preparePredicatesDeviceTypes(CriteriaBuilder cb, CriteriaQuery cq, Root<WipDeviceType> from, Boolean deleted,
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
Boolean includeHistory) {
List<Predicate> predicates = new ArrayList<>();
if (!Boolean.TRUE.equals(includeHistory)) {
// purpose of Naming to show valid entries
// therefore
// exclude some values unless history requested
// make sure to not exclude present and future values (latest approved and pending)
//
// condition(s)
// exclude content (with latest) before latest
// exclude content (with latest) after latest (cancelled, rejected)
// keep most recent content (without latest) (to have most recent in line of uuid without latest)
// <-->
// select * from structure s
// where (
// not (exists (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.id < (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true))
// and not (exists (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.id > (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.status in ('CANCELLED', 'REJECTED'))
// and not (not exists (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.id < (select max(s2.id) from structure s2 where s2."uuid" = s."uuid" and s2.latest=false))
// )
// <-->
// not (exists (subquery id) and s.id < (subquery id))
// and not (exists (subquery id) and s.id > (subquery id) and s.status in ('CANCELLED', 'REJECTED'))
// and not (not exists (subquery id) and s.id < (subquery 2))
//
// note
// persistence libraries may optimize query
// e.g. change (!a and !b) to !(a or b)
Subquery<Long> sub = cq.subquery(Long.class);
Root<WipDeviceType> fromSub = sub.from(WipDeviceType.class);
sub.where(cb.and(
cb.equal(fromSub.get(WipNameStructure.FIELD_UUID), from.get(WipNameStructure.FIELD_UUID)),
cb.equal(fromSub.get(WipNameStructure.FIELD_LATEST), Boolean.TRUE)
));
sub.select(fromSub.get(Persistable.FIELD_ID));
Subquery<Long> sub2 = cq.subquery(Long.class);
Root<WipDeviceType> fromSub2 = sub2.from(WipDeviceType.class);
sub2.where(cb.and(
cb.equal(fromSub2.get(WipNameStructure.FIELD_UUID), from.get(WipNameStructure.FIELD_UUID)),
cb.equal(fromSub2.get(WipNameStructure.FIELD_LATEST), Boolean.FALSE)
));
sub2.select(cb.max(fromSub2.get(Persistable.FIELD_ID)));
Predicate predicateExclude =
cb.and(
cb.not(cb.and(
cb.exists(sub),
cb.lessThan(from.get(Persistable.FIELD_ID).as(Long.class), sub))),
cb.not(cb.and(
cb.exists(sub),
cb.greaterThan(from.get(Persistable.FIELD_ID).as(Long.class), sub),
cb.or(
cb.equal(from.get(WipNameStructure.FIELD_STATUS), Status.CANCELLED),
cb.equal(from.get(WipNameStructure.FIELD_STATUS), Status.REJECTED)))),
cb.not(cb.and(
cb.not(cb.exists(sub)),
cb.lessThan(from.get(Persistable.FIELD_ID).as(Long.class), sub2)))
);
predicates.add(predicateExclude);
}
if (deleted != null) {
predicates.add(cb.equal(from.get(WipNameStructure.FIELD_DELETED), deleted));
}
// prepare pattern
// jpa query characters % and _
// remove excess % characters
if (!StringUtils.isEmpty(uuid)) {
predicates.add(cb.and(cb.equal(from.get(WipNameStructure.FIELD_UUID), RepositoryUtil.preparePattern(uuid))));
}
if (!StringUtils.isEmpty(parentUuid)) {
predicates.add(cb.and(cb.equal(from.get(WipDeviceType.FIELD_PARENT_UUID), RepositoryUtil.preparePattern(parentUuid))));
}
if (!StringUtils.isEmpty(mnemonic)) {
predicates.add(cb.and(cb.like(from.get(WipStructure.FIELD_MNEMONIC), RepositoryUtil.preparePattern(mnemonic))));
}
if (!StringUtils.isEmpty(mnemonicEquivalence)) {
predicates.add(cb.and(cb.like(from.get(WipStructure.FIELD_MNEMONIC_EQUIVALENCE), RepositoryUtil.preparePattern(mnemonicEquivalence))));
}
if (!StringUtils.isEmpty(mnemonicPath)) {
predicates.add(cb.and(cb.like(cb.function(WipDeviceType.FUNCTION_GET_MNEMONIC_PATH_DEVICETYPE, String.class, from.get(WipNameStructure.FIELD_UUID)), RepositoryUtil.preparePattern(mnemonicPath))));
}
if (!StringUtils.isEmpty(description)) {
predicates.add(cb.and(cb.like(from.get(WipNameStructure.FIELD_DESCRIPTION), RepositoryUtil.preparePattern(description))));
}
if (!StringUtils.isEmpty(who)) {
predicates.add(cb.and(cb.like(from.get(WipNameStructure.FIELD_PROCESSED_BY), RepositoryUtil.preparePattern(who))));
}
return predicates;
}
/**
* Prepare order by query expression.
*
* @param root root type in the from clause
* @param orderBy field on which to order by
* @return order by query expression
*/
private Expression<String> orderBy(Root<WipDeviceType> root, FieldStructure orderBy) {
if (FieldStructure.UUID.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_UUID);
} else if (FieldStructure.PARENT.equals(orderBy)) {
return root.get(WipDeviceType.FIELD_PARENT_UUID);
} else if (FieldStructure.MNEMONIC.equals(orderBy)) {
return root.get(WipStructure.FIELD_MNEMONIC);
} else if (FieldStructure.MNEMONICPATH.equals(orderBy)) {
return root.get(WipStructure.FIELD_MNEMONIC);
} else if (FieldStructure.ORDERING.equals(orderBy)) {
return root.get(WipStructure.FIELD_ORDERING);
} else if (FieldStructure.DESCRIPTION.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_DESCRIPTION);
} else if (FieldStructure.WHEN.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_PROCESSED);
} else {
return root.get(WipStructure.FIELD_MNEMONIC);
}
}
/**
* Count device types history.
*
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @return count of device types
*/
public Long countDeviceTypesHistory(
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who) {
// note
// use of function for mnemonic path
// deleted - null
// includeHistory - true
// where
// queryFields, queryValues
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<WipDeviceType> from = cq.from(WipDeviceType.class);
Subquery<String> sub = cq.subquery(String.class);
Root<WipDeviceType> fromSub = sub.from(WipDeviceType.class);
sub.where(cb.and(preparePredicatesDeviceTypes(cb, cq, fromSub, null,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
Boolean.TRUE).toArray(new Predicate[0])));
sub.select(fromSub.get(WipNameStructure.FIELD_UUID));
cq.where(cb.and(cb.in(from.get(WipNameStructure.FIELD_UUID)).value(sub)));
cq.select(cb.count(from));
return em.createQuery(cq).getSingleResult();
}
/**
* Find device types history.
*
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param orderBy order by
* @param isAsc is ascending
* @return list of device types
*/
public List<WipDeviceType> readDeviceTypesHistory(
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
FieldStructure orderBy, Boolean isAsc) {
// note
// use of function for mnemonic path
// deleted - null
// includeHistory - true
// where
// queryFields, queryValues
// order
// orderBy, isAsc
// paging
// outside of method
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<WipDeviceType> cq = cb.createQuery(WipDeviceType.class);
Root<WipDeviceType> from = cq.from(WipDeviceType.class);
Subquery<String> sub = cq.subquery(String.class);
Root<WipDeviceType> fromSub = sub.from(WipDeviceType.class);
sub.where(cb.and(preparePredicatesDeviceTypes(cb, cq, fromSub, null,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
Boolean.TRUE).toArray(new Predicate[0])));
sub.select(fromSub.get(WipNameStructure.FIELD_UUID));
cq.where(cb.and(cb.in(from.get(WipNameStructure.FIELD_UUID)).value(sub)));
cq.select(from);
if (orderBy != null) {
Expression<String> exp = orderBy(from, orderBy);
if (BooleanUtils.toBoolean(isAsc)) {
cq.orderBy(cb.asc(exp));
} else {
cq.orderBy(cb.desc(exp));
}
}
return em.createQuery(cq).getResultList();
}
/**
* Persist device type into persistence context.
*
* @param deviceType device type
*/
public void createDeviceType(WipDeviceType deviceType) {
em.persist(deviceType);
}
/**
* Merge device type into persistence context.
*
* @param deviceType device type
*/
public void updateDeviceType(WipDeviceType deviceType) {
em.merge(deviceType);
}
}
/*
* Copyright (C) 2021 European Spallation Source ERIC.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.openepics.names.repository.wip;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.openepics.names.repository.model.Persistable;
import org.openepics.names.repository.model.wip.WipDiscipline;
import org.openepics.names.repository.model.wip.WipNameStructure;
import org.openepics.names.repository.model.wip.WipStructure;
import org.openepics.names.rest.beans.FieldStructure;
import org.openepics.names.rest.beans.Status;
import org.openepics.names.util.RepositoryUtil;
import org.springframework.stereotype.Repository;
/**
* Handle discipline information in JPA.
*
* @author Lars Johansson
*/
@Repository
public class WipDisciplineRepository {
@PersistenceContext
private EntityManager em;
/**
* Count disciplines.
*
* @param deleted deleted
* @param uuid uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param includeHistory include history
* @return count of disciplines
*/
public Long countDisciplines(Boolean deleted,
String uuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
Boolean includeHistory) {
// note
// use of function for mnemonic path
// where
// deleted
// queryFields, queryValues
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<WipDiscipline> from = cq.from(WipDiscipline.class);
cq.where(cb.and(preparePredicatesDisciplines(cb, cq, from, deleted,
uuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
includeHistory).toArray(new Predicate[0])));
cq.select(cb.count(from));
return em.createQuery(cq).getSingleResult();
}
/**
* Find disciplines.
*
* @param deleted deleted
* @param uuid uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @return list of disciplines
*/
public List<WipDiscipline> readDisciplines(Boolean deleted,
String uuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who) {
return readDisciplines(deleted,
uuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
Boolean.FALSE, null, null, null, null);
}
/**
* Find disciplines.
*
* @param deleted deleted
* @param uuid uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param includeHistory include history
* @param orderBy order by
* @param isAsc is ascending
* @param offset offset
* @param limit limit
* @return list of disciplines
*/
public List<WipDiscipline> readDisciplines(Boolean deleted,
String uuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
Boolean includeHistory, FieldStructure orderBy, Boolean isAsc, Integer offset, Integer limit) {
// note
// use of function for mnemonic path
// where
// latest, deleted
// queryFields, queryValues
// order
// orderBy, isAsc
// paging
// offset, limit
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<WipDiscipline> cq = cb.createQuery(WipDiscipline.class);
Root<WipDiscipline> from = cq.from(WipDiscipline.class);
cq.where(cb.and(preparePredicatesDisciplines(cb, cq, from, deleted,
uuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
includeHistory).toArray(new Predicate[0])));
cq.select(from);
if (orderBy != null) {
Expression<String> exp = orderBy(from, orderBy);
if (BooleanUtils.toBoolean(isAsc)) {
cq.orderBy(cb.asc(exp));
} else {
cq.orderBy(cb.desc(exp));
}
}
TypedQuery<WipDiscipline> query = em.createQuery(cq);
if (offset != null && limit != null) {
query.setFirstResult(offset * limit);
query.setMaxResults(limit);
}
return query.getResultList();
}
/**
* Prepare predicates for disciplines.
*
* @param cb criteria builder
* @param cq criteria query
* @param from criteria query root
* @param deleted deleted
* @param uuid uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param includeHistory include history
* @return list of predicates
*/
private List<Predicate> preparePredicatesDisciplines(CriteriaBuilder cb, CriteriaQuery cq, Root<WipDiscipline> from, Boolean deleted,
String uuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
Boolean includeHistory) {
List<Predicate> predicates = new ArrayList<>();
if (!Boolean.TRUE.equals(includeHistory)) {
// purpose of Naming to show valid entries
// therefore
// exclude some values unless history requested
// make sure to not exclude present and future values (latest approved and pending)
//
// condition(s)
// exclude content (with latest) before latest
// exclude content (with latest) after latest (cancelled, rejected)
// keep most recent content (without latest) (to have most recent in line of uuid without latest)
// <-->
// select * from structure s
// where (
// not (exists (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.id < (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true))
// and not (exists (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.id > (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.status in ('CANCELLED', 'REJECTED'))
// and not (not exists (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.id < (select max(s2.id) from structure s2 where s2."uuid" = s."uuid" and s2.latest=false))
// )
// <-->
// not (exists (subquery id) and s.id < (subquery id))
// and not (exists (subquery id) and s.id > (subquery id) and s.status in ('CANCELLED', 'REJECTED'))
// and not (not exists (subquery id) and s.id < (subquery 2))
//
// note
// persistence libraries may optimize query
// e.g. change (!a and !b) to !(a or b)
Subquery<Long> sub = cq.subquery(Long.class);
Root<WipDiscipline> fromSub = sub.from(WipDiscipline.class);
sub.where(cb.and(
cb.equal(fromSub.get(WipNameStructure.FIELD_UUID), from.get(WipNameStructure.FIELD_UUID)),
cb.equal(fromSub.get(WipNameStructure.FIELD_LATEST), Boolean.TRUE)
));
sub.select(fromSub.get(Persistable.FIELD_ID));
Subquery<Long> sub2 = cq.subquery(Long.class);
Root<WipDiscipline> fromSub2 = sub2.from(WipDiscipline.class);
sub2.where(cb.and(
cb.equal(fromSub2.get(WipNameStructure.FIELD_UUID), from.get(WipNameStructure.FIELD_UUID)),
cb.equal(fromSub2.get(WipNameStructure.FIELD_LATEST), Boolean.FALSE)
));
sub2.select(cb.max(fromSub2.get(Persistable.FIELD_ID)));
Predicate predicateExclude =
cb.and(
cb.not(cb.and(
cb.exists(sub),
cb.lessThan(from.get(Persistable.FIELD_ID).as(Long.class), sub))),
cb.not(cb.and(
cb.exists(sub),
cb.greaterThan(from.get(Persistable.FIELD_ID).as(Long.class), sub),
cb.or(
cb.equal(from.get(WipNameStructure.FIELD_STATUS), Status.CANCELLED),
cb.equal(from.get(WipNameStructure.FIELD_STATUS), Status.REJECTED)))),
cb.not(cb.and(
cb.not(cb.exists(sub)),
cb.lessThan(from.get(Persistable.FIELD_ID).as(Long.class), sub2)))
);
predicates.add(predicateExclude);
}
if (deleted != null) {
predicates.add(cb.equal(from.get(WipNameStructure.FIELD_DELETED), deleted));
}
// prepare pattern
// jpa query characters % and _
// remove excess % characters
if (!StringUtils.isEmpty(uuid)) {
predicates.add(cb.and(cb.equal(from.get(WipNameStructure.FIELD_UUID), RepositoryUtil.preparePattern(uuid))));
}
if (!StringUtils.isEmpty(mnemonic)) {
predicates.add(cb.and(cb.like(from.get(WipStructure.FIELD_MNEMONIC), RepositoryUtil.preparePattern(mnemonic))));
}
if (!StringUtils.isEmpty(mnemonicEquivalence)) {
predicates.add(cb.and(cb.like(from.get(WipStructure.FIELD_MNEMONIC_EQUIVALENCE), RepositoryUtil.preparePattern(mnemonicEquivalence))));
}
if (!StringUtils.isEmpty(mnemonicPath)) {
predicates.add(cb.and(cb.like(from.get(WipStructure.FIELD_MNEMONIC), RepositoryUtil.preparePattern(mnemonicPath))));
}
if (!StringUtils.isEmpty(description)) {
predicates.add(cb.and(cb.like(from.get(WipNameStructure.FIELD_DESCRIPTION), RepositoryUtil.preparePattern(description))));
}
if (!StringUtils.isEmpty(who)) {
predicates.add(cb.and(cb.like(from.get(WipNameStructure.FIELD_PROCESSED_BY), RepositoryUtil.preparePattern(who))));
}
return predicates;
}
/**
* Prepare order by query expression.
*
* @param root root type in the from clause
* @param orderBy field on which to order by
* @return order by query expression
*/
private Expression<String> orderBy(Root<WipDiscipline> root, FieldStructure orderBy) {
// no parent for discipline
if (FieldStructure.UUID.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_UUID);
} else if (FieldStructure.MNEMONIC.equals(orderBy)) {
return root.get(WipStructure.FIELD_MNEMONIC);
} else if (FieldStructure.MNEMONICPATH.equals(orderBy)) {
return root.get(WipStructure.FIELD_MNEMONIC);
} else if (FieldStructure.ORDERING.equals(orderBy)) {
return root.get(WipStructure.FIELD_ORDERING);
} else if (FieldStructure.DESCRIPTION.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_DESCRIPTION);
} else if (FieldStructure.WHEN.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_PROCESSED);
} else {
return root.get(WipStructure.FIELD_MNEMONIC);
}
}
/**
* Count disciplines history.
*
* @param uuid uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @return count of disciplines
*/
public Long countDisciplinesHistory(
String uuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who) {
// note
// deleted - null
// includeHistory - true
// where
// queryFields, queryValues
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<WipDiscipline> from = cq.from(WipDiscipline.class);
Subquery<String> sub = cq.subquery(String.class);
Root<WipDiscipline> fromSub = sub.from(WipDiscipline.class);
sub.where(cb.and(preparePredicatesDisciplines(cb, cq, fromSub, null,
uuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
Boolean.TRUE).toArray(new Predicate[0])));
sub.select(fromSub.get(WipNameStructure.FIELD_UUID));
cq.where(cb.and(cb.in(from.get(WipNameStructure.FIELD_UUID)).value(sub)));
cq.select(cb.count(from));
return em.createQuery(cq).getSingleResult();
}
/**
* Find disciplines history.
*
* @param uuid uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param orderBy order by
* @param isAsc is ascending
* @return list of disciplines
*/
public List<WipDiscipline> readDisciplinesHistory(
String uuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
FieldStructure orderBy, Boolean isAsc) {
// note
// deleted - null
// includeHistory - true
// where
// queryFields, queryValues
// order
// orderBy, isAsc
// paging
// outside of method
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<WipDiscipline> cq = cb.createQuery(WipDiscipline.class);
Root<WipDiscipline> from = cq.from(WipDiscipline.class);
Subquery<String> sub = cq.subquery(String.class);
Root<WipDiscipline> fromSub = sub.from(WipDiscipline.class);
sub.where(cb.and(preparePredicatesDisciplines(cb, cq, fromSub, null,
uuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
Boolean.TRUE).toArray(new Predicate[0])));
sub.select(fromSub.get(WipNameStructure.FIELD_UUID));
cq.where(cb.and(cb.in(from.get(WipNameStructure.FIELD_UUID)).value(sub)));
cq.select(from);
if (orderBy != null) {
Expression<String> exp = orderBy(from, orderBy);
if (BooleanUtils.toBoolean(isAsc)) {
cq.orderBy(cb.asc(exp));
} else {
cq.orderBy(cb.desc(exp));
}
}
return em.createQuery(cq).getResultList();
}
/**
* Persist discipline into persistence context.
*
* @param discipline discipline
*/
public void createDiscipline(WipDiscipline discipline) {
em.persist(discipline);
}
/**
* Merge discipline into persistence context.
*
* @param discipline discipline
*/
public void updateDiscipline(WipDiscipline discipline) {
em.merge(discipline);
}
}
/*
* Copyright (C) 2021 European Spallation Source ERIC.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.openepics.names.repository.wip;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.openepics.names.repository.model.wip.WipName;
import org.openepics.names.repository.model.wip.WipNameStructure;
import org.openepics.names.rest.beans.FieldName;
import org.openepics.names.util.RepositoryUtil;
import org.springframework.stereotype.Repository;
/**
* Handle name information in JPA.
*
* @author Lars Johansson
*/
@Repository
public class WipNameRepository {
/**
* Used to decide how to traverse structure references for names.
*/
public enum NameByStructure {
NAME_BY_SYSTEMGROUP,
NAME_BY_SYSTEMGROUP_THROUGH_SYSTEM,
NAME_BY_SYSTEMGROUP_THROUGH_SUBSYSTEM,
NAME_BY_SYSTEM,
NAME_BY_SYSTEM_THROUGH_SUBSYSTEM,
NAME_BY_SUBSYSTEM,
NAME_BY_DISCIPLINE_THROUGH_DEVICETYPE,
NAME_BY_DEVICEGROUP_THROUGH_DEVICETYPE,
NAME_BY_DEVICETYPE;
}
@PersistenceContext
private EntityManager em;
/**
* Count names.
*
* @param deleted deleted
* @param uuid uuid
* @param name name
* @param nameEquivalence name equivalence
* @param systemStructure system structure mnemonic
* @param deviceStructure device structure mnemonic
* @param index index
* @param description description
* @param who who
* @param includeHistory include history
* @return count of names
*/
public Long countNames(Boolean deleted,
String uuid, String name, String nameEquivalence, String systemStructure, String deviceStructure, String index, String description, String who,
Boolean includeHistory) {
// note
// use of function for mnemonic path
// where
// latest, deleted
// queryFields, queryValues
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<WipName> from = cq.from(WipName.class);
cq.where(cb.and(preparePredicatesNames(cb, from, deleted,
uuid, name, nameEquivalence, systemStructure, deviceStructure, index, description, who,
includeHistory).toArray(new Predicate[0])));
cq.select(cb.count(from));
return em.createQuery(cq).getSingleResult();
}
/**
* Find names.
*
* @param deleted deleted
* @param uuid uuid
* @param name name
* @param nameEquivalence name equivalence
* @param systemStructure system structure mnemonic
* @param deviceStructure device structure mnemonic
* @param index index
* @param description description
* @param who who
* @return list of names
*/
public List<WipName> readNames(Boolean deleted,
String uuid, String name, String nameEquivalence, String systemStructure, String deviceStructure, String index, String description, String who) {
return readNames(deleted,
uuid, name, nameEquivalence, systemStructure, deviceStructure, index, description, who,
Boolean.FALSE, null, null, null, null);
}
/**
* Find names.
*
* @param deleted deleted
* @param uuid uuid
* @param name name
* @param nameEquivalence name equivalence
* @param systemStructure system structure mnemonic
* @param deviceStructure device structure mnemonic
* @param index index
* @param description description
* @param who who
* @param includeHistory include history
* @param orderBy order by
* @param isAsc is ascending
* @param offset offset
* @param limit limit
* @return list of names
*/
public List<WipName> readNames(Boolean deleted,
String uuid, String name, String nameEquivalence, String systemStructure, String deviceStructure, String index, String description, String who,
Boolean includeHistory, FieldName orderBy, Boolean isAsc, Integer offset, Integer limit) {
// note
// use of function for mnemonic path
// where
// latest, deleted
// queryFields, queryValues
// order
// orderBy, isAsc
// paging
// offset, limit
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<WipName> cq = cb.createQuery(WipName.class);
Root<WipName> from = cq.from(WipName.class);
cq.where(cb.and(preparePredicatesNames(cb, from, deleted,
uuid, name, nameEquivalence, systemStructure, deviceStructure, index, description, who,
includeHistory).toArray(new Predicate[0])));
cq.select(from);
if (orderBy != null) {
Expression<String> exp = orderBy(cb, from, orderBy);
if (BooleanUtils.toBoolean(isAsc)) {
cq.orderBy(cb.asc(exp));
} else {
cq.orderBy(cb.desc(exp));
}
}
TypedQuery<WipName> query = em.createQuery(cq);
if (offset != null && limit != null) {
query.setFirstResult(offset * limit);
query.setMaxResults(limit);
}
return query.getResultList();
}
/**
* Prepare predicates for names.
*
* @param cb criteria builder
* @param from criteria query root
* @param deleted deleted
* @param uuid uuid
* @param name name
* @param nameEquivalence name equivalence
* @param systemStructure system structure mnemonic
* @param deviceStructure device structure mnemonic
* @param index index
* @param description description
* @param who who
* @param includeHistory include history
* @return list of predicates
*/
private List<Predicate> preparePredicatesNames(CriteriaBuilder cb, Root<WipName> from, Boolean deleted,
String uuid, String name, String nameEquivalence, String systemStructure, String deviceStructure, String index, String description, String who,
Boolean includeHistory) {
List<Predicate> predicates = new ArrayList<>();
if (!Boolean.TRUE.equals(includeHistory)) {
// purpose of Naming to show valid entries
// therefore
// exclude some values unless history requested
// make sure to not exclude present and future values
//
// exclude not latest
// select * from Name n where
// not(n.latest = false)
Predicate predicateNotLatest = cb.equal(from.get(WipNameStructure.FIELD_LATEST), Boolean.FALSE);
Predicate predicateExclude = cb.not(cb.and(predicateNotLatest));
predicates.add(predicateExclude);
}
if (deleted != null) {
predicates.add(cb.equal(from.get(WipNameStructure.FIELD_DELETED), deleted));
}
// prepare pattern
// jpa query characters % and _
// remove excess % characters
if (!StringUtils.isEmpty(uuid)) {
predicates.add(cb.and(cb.equal(from.get(WipNameStructure.FIELD_UUID), RepositoryUtil.preparePattern(uuid))));
}
if (!StringUtils.isEmpty(name)) {
predicates.add(cb.and(cb.like(from.get(WipName.FIELD_CONVENTION_NAME), RepositoryUtil.preparePattern(name))));
}
if (!StringUtils.isEmpty(nameEquivalence)) {
predicates.add(cb.and(cb.like(from.get(WipName.FIELD_CONVENTION_NAME_EQUIVALENCE), RepositoryUtil.preparePattern(nameEquivalence))));
}
if (!StringUtils.isEmpty(systemStructure)) {
predicates.add(cb.and(cb.like(cb.function(WipNameStructure.FUNCTION_GET_MNEMONIC_PATH_SYSTEM_STRUCTURE, String.class, from.get(WipName.FIELD_CONVENTION_NAME)), RepositoryUtil.preparePattern(systemStructure))));
}
if (!StringUtils.isEmpty(deviceStructure)) {
predicates.add(cb.and(cb.like(cb.function(WipNameStructure.FUNCTION_GET_MNEMONIC_PATH_DEVICE_STRUCTURE, String.class, from.get(WipName.FIELD_CONVENTION_NAME)), RepositoryUtil.preparePattern(deviceStructure))));
}
if (!StringUtils.isEmpty(index)) {
predicates.add(cb.and(cb.like(cb.function(WipNameStructure.FUNCTION_GET_INSTANCE_INDEX, String.class, from.get(WipName.FIELD_CONVENTION_NAME)), RepositoryUtil.preparePattern(index))));
}
if (!StringUtils.isEmpty(description)) {
predicates.add(cb.and(cb.like(from.get(WipNameStructure.FIELD_DESCRIPTION), RepositoryUtil.preparePattern(description))));
}
if (!StringUtils.isEmpty(who)) {
predicates.add(cb.and(cb.like(from.get(WipNameStructure.FIELD_REQUESTED_BY), RepositoryUtil.preparePattern(who))));
}
return predicates;
}
/**
* Prepare order by query expression.
*
* @param cb criteria builder
* @param root root type in the from clause
* @param orderBy field on which to order by
* @return order by query expression
*/
private Expression<String> orderBy(CriteriaBuilder cb, Root<WipName> root, FieldName orderBy) {
if (FieldName.UUID.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_UUID);
} else if (FieldName.SYSTEMSTRUCTURE.equals(orderBy)) {
return cb.function(WipNameStructure.FUNCTION_GET_MNEMONIC_PATH_SYSTEM_STRUCTURE, String.class, root.get(WipName.FIELD_CONVENTION_NAME));
} else if (FieldName.DEVICESTRUCTURE.equals(orderBy)) {
return cb.function(WipNameStructure.FUNCTION_GET_MNEMONIC_PATH_DEVICE_STRUCTURE, String.class, root.get(WipName.FIELD_CONVENTION_NAME));
} else if (FieldName.INDEX.equals(orderBy)) {
return cb.function(WipNameStructure.FUNCTION_GET_INSTANCE_INDEX, String.class, root.get(WipName.FIELD_CONVENTION_NAME));
} else if (FieldName.DESCRIPTION.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_DESCRIPTION);
} else if (FieldName.WHEN.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_REQUESTED);
} else {
return root.get(WipName.FIELD_CONVENTION_NAME);
}
}
/**
* Count names history.
*
* @param uuid uuid
* @param name name
* @param nameEquivalence name equivalence
* @param systemStructure system structure mnemonic
* @param deviceStructure device structure mnemonic
* @param index index
* @param description description
* @param who who
* @return count of names
*/
public Long countNamesHistory(
String uuid, String name, String nameEquivalence, String systemStructure, String deviceStructure, String index, String description, String who) {
// note
// use of function for mnemonic path
// deleted - null
// includeHistory - true
// where
// queryFields, queryValues
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<WipName> from = cq.from(WipName.class);
Subquery<String> sub = cq.subquery(String.class);
Root<WipName> fromSub = sub.from(WipName.class);
sub.where(cb.and(preparePredicatesNames(cb, fromSub, null,
uuid, name, nameEquivalence, systemStructure, deviceStructure, index, description, who,
Boolean.TRUE).toArray(new Predicate[0])));
sub.select(fromSub.get(WipNameStructure.FIELD_UUID));
cq.where(cb.and(cb.in(from.get(WipNameStructure.FIELD_UUID)).value(sub)));
cq.select(cb.count(from));
return em.createQuery(cq).getSingleResult();
}
/**
* Find names history.
*
* @param uuid uuid
* @param name name
* @param nameEquivalence name equivalence
* @param systemStructure system structure mnemonic
* @param deviceStructure device structure mnemonic
* @param index index
* @param description description
* @param who who
* @param orderBy order by
* @param isAsc is ascending
* @param offset offset
* @param limit limit
* @return list of names
*/
public List<WipName> readNamesHistory(
String uuid, String name, String nameEquivalence, String systemStructure, String deviceStructure, String index, String description, String who,
FieldName orderBy, Boolean isAsc, Integer offset, Integer limit) {
// note
// use of function for mnemonic path
// deleted - null
// includeHistory - true
// where
// queryFields, queryValues
// order
// orderBy, isAsc
// paging
// offset, limit
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<WipName> cq = cb.createQuery(WipName.class);
Root<WipName> from = cq.from(WipName.class);
Subquery<String> sub = cq.subquery(String.class);
Root<WipName> fromSub = sub.from(WipName.class);
sub.where(cb.and(preparePredicatesNames(cb, fromSub, null,
uuid, name, nameEquivalence, systemStructure, deviceStructure, index, description, who,
Boolean.TRUE).toArray(new Predicate[0])));
sub.select(fromSub.get(WipNameStructure.FIELD_UUID));
cq.where(cb.and(cb.in(from.get(WipNameStructure.FIELD_UUID)).value(sub)));
cq.select(from);
if (orderBy != null) {
Expression<String> exp = orderBy(cb, from, orderBy);
if (BooleanUtils.toBoolean(isAsc)) {
cq.orderBy(cb.asc(exp));
} else {
cq.orderBy(cb.desc(exp));
}
}
TypedQuery<WipName> query = em.createQuery(cq);
if (offset != null && limit != null) {
query.setFirstResult(offset * limit);
query.setMaxResults(limit);
}
return query.getResultList();
}
/**
* Find names by structure uuid.
*
* @param nameByStructure kind of read operation, used to decide how to traverse structure references for names
* @param uuid structure uuid
* @param deleted deleted
* @param orderBy order by
* @param isAsc is ascending
* @return list of names
*/
@SuppressWarnings("unchecked")
public List<WipName> readNamesLatestByStructure(NameByStructure nameByStructure, String uuid, Boolean deleted,
FieldName orderBy, Boolean isAsc) {
// must have NameByStructure
if (nameByStructure == null || StringUtils.isEmpty(uuid)) {
return Lists.newArrayList();
}
StringBuilder sql = new StringBuilder();
switch (nameByStructure) {
case NAME_BY_SYSTEMGROUP:
sql.append("SELECT n FROM WipName n, WipSystemGroup sg "
+ "WHERE n.latest = true "
+ "AND sg.uuid = n.systemGroupUuid "
+ "AND sg.latest = true "
+ "AND sg.uuid = :sUuid");
break;
case NAME_BY_SYSTEMGROUP_THROUGH_SYSTEM:
sql.append("SELECT n FROM WipName n, WipSystem sys, WipSystemGroup sg "
+ "WHERE n.latest = true "
+ "AND sys.uuid = n.systemUuid "
+ "AND sys.latest = true "
+ "AND sg.uuid = sys.parentUuid "
+ "AND sg.latest = true "
+ "AND sg.uuid = :sUuid");
break;
case NAME_BY_SYSTEMGROUP_THROUGH_SUBSYSTEM:
sql.append("SELECT n FROM WipName n, WipSubsystem sub, WipSystem sys, WipSystemGroup sg "
+ "WHERE n.latest = true "
+ "AND sub.uuid = n.subsystemUuid "
+ "AND sub.latest = true "
+ "AND sys.uuid = sub.parentUuid "
+ "AND sys.latest = true "
+ "AND sg.uuid = sys.parentUuid "
+ "AND sg.latest = true "
+ "AND sg.uuid = :sUuid");
break;
case NAME_BY_SYSTEM:
sql.append("SELECT n FROM WipName n, WipSystem sys "
+ "WHERE n.latest = true "
+ "AND sys.uuid = n.systemUuid "
+ "AND sys.latest = true "
+ "AND sys.uuid = :sUuid");
break;
case NAME_BY_SYSTEM_THROUGH_SUBSYSTEM:
sql.append("SELECT n FROM WipName n, WipSubsystem sub, WipSystem sys "
+ "WHERE n.latest = true "
+ "AND sub.uuid = n.subsystemUuid "
+ "AND sub.latest = true "
+ "AND sys.uuid = sub.parentUuid "
+ "AND sys.latest = true "
+ "AND sys.uuid = :sUuid");
break;
case NAME_BY_SUBSYSTEM:
sql.append("SELECT n FROM WipName n, WipSubsystem sub "
+ "WHERE n.latest = true "
+ "AND sub.uuid = n.subsystemUuid "
+ "AND sub.latest = true "
+ "AND sub.uuid = :sUuid");
break;
case NAME_BY_DISCIPLINE_THROUGH_DEVICETYPE:
sql.append("SELECT n FROM WipName n, WipDeviceType dt, WipDeviceGroup dg, WipDiscipline di "
+ "WHERE n.latest = true "
+ "AND dt.uuid = n.deviceTypeUuid "
+ "AND dt.latest = true "
+ "AND dg.uuid = dt.parentUuid "
+ "AND dg.latest = true "
+ "AND di.uuid = dg.parentUuid "
+ "AND di.latest = true "
+ "AND di.uuid = :sUuid");
break;
case NAME_BY_DEVICEGROUP_THROUGH_DEVICETYPE:
sql.append("SELECT n FROM WipName n, WipDeviceType dt, WipDeviceGroup dg "
+ "WHERE n.latest = true "
+ "AND dt.uuid = n.deviceTypeUuid "
+ "AND dt.latest = true "
+ "AND dg.uuid = dt.parentUuid "
+ "AND dg.latest = true "
+ "AND dg.uuid = :sUuid");
break;
case NAME_BY_DEVICETYPE:
sql.append("SELECT n FROM WipName n, WipDeviceType dt "
+ "WHERE n.latest = true "
+ "AND dt.uuid = n.deviceTypeUuid "
+ "AND dt.latest = true "
+ "AND dt.uuid = :sUuid");
break;
default: return Lists.newArrayList();
}
if (deleted != null) {
sql.append(" and n.deleted = :nDeleted");
}
StringBuilder sqlOrderBy = new StringBuilder();
if (orderBy != null) {
sqlOrderBy.append(" order by ");
if (FieldName.UUID.equals(orderBy)) {
sqlOrderBy.append("n.");
sqlOrderBy.append(WipNameStructure.FIELD_UUID);
} else if (FieldName.SYSTEMSTRUCTURE.equals(orderBy)) {
sqlOrderBy.append(WipNameStructure.FUNCTION_GET_MNEMONIC_PATH_SYSTEM_STRUCTURE);
sqlOrderBy.append("(n.conventionName)");
} else if (FieldName.DEVICESTRUCTURE.equals(orderBy)) {
sqlOrderBy.append(WipNameStructure.FUNCTION_GET_MNEMONIC_PATH_DEVICE_STRUCTURE);
sqlOrderBy.append("(n.conventionName)");
} else if (FieldName.INDEX.equals(orderBy)) {
sqlOrderBy.append(WipNameStructure.FUNCTION_GET_INSTANCE_INDEX);
sqlOrderBy.append("(n.conventionName)");
} else if (FieldName.DESCRIPTION.equals(orderBy)) {
sqlOrderBy.append("n.");
sqlOrderBy.append(WipNameStructure.FIELD_DESCRIPTION);
} else if (FieldName.WHEN.equals(orderBy)) {
sqlOrderBy.append("n.");
sqlOrderBy.append(WipNameStructure.FIELD_REQUESTED);
} else {
sqlOrderBy.append("n.");
sqlOrderBy.append(WipName.FIELD_CONVENTION_NAME);
}
if (BooleanUtils.toBoolean(isAsc)) {
sqlOrderBy.append(" asc");
} else {
sqlOrderBy.append(" desc");
}
}
if (orderBy != null) {
sql.append(sqlOrderBy.toString());
}
Query query = em.createQuery(sql.toString(), WipName.class).setParameter("sUuid", uuid);
if (deleted != null) {
query.setParameter("nDeleted", deleted);
}
return query.getResultList();
}
/**
* Persist name into persistence context.
*
* @param name name
*/
public void createName(WipName name) {
em.persist(name);
}
/**
* Merge name into persistence context.
*
* @param name name
*/
public void updateName(WipName name) {
em.merge(name);
}
}
/*
* Copyright (C) 2021 European Spallation Source ERIC.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.openepics.names.repository.wip;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.openepics.names.repository.model.Persistable;
import org.openepics.names.repository.model.wip.WipNameStructure;
import org.openepics.names.repository.model.wip.WipStructure;
import org.openepics.names.repository.model.wip.WipSubsystem;
import org.openepics.names.rest.beans.FieldStructure;
import org.openepics.names.rest.beans.Status;
import org.openepics.names.util.RepositoryUtil;
import org.springframework.stereotype.Repository;
/**
* Handle subsystem information in JPA.
*
* @author Lars Johansson
*/
@Repository
public class WipSubsystemRepository {
@PersistenceContext
private EntityManager em;
/**
* Count subsystems.
*
* @param deleted deleted
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param includeHistory include history
* @return count of subsystems
*/
public Long countSubsystems(Boolean deleted,
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
Boolean includeHistory) {
// note
// use of function for mnemonic path
// where
// deleted
// queryFields, queryValues
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<WipSubsystem> from = cq.from(WipSubsystem.class);
cq.where(cb.and(preparePredicatesSubsystems(cb, cq, from, deleted,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
includeHistory).toArray(new Predicate[0])));
cq.select(cb.count(from));
return em.createQuery(cq).getSingleResult();
}
/**
* Find subsystems.
*
* @param deleted deleted
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @return list of subsystems
*/
public List<WipSubsystem> readSubsystems(Boolean deleted,
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who) {
return readSubsystems(deleted,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
Boolean.FALSE, null, null, null, null);
}
/**
* Find subsystems.
*
* @param deleted deleted
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param includeHistory include history
* @param orderBy order by
* @param isAsc is ascending
* @param offset offset
* @param limit limit
* @return list of subsystems
*/
public List<WipSubsystem> readSubsystems(Boolean deleted,
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
Boolean includeHistory, FieldStructure orderBy, Boolean isAsc, Integer offset, Integer limit) {
// note
// use of function for mnemonic path
// where
// deleted
// queryFields, queryValues
// order
// orderBy, isAsc
// paging
// offset, limit
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<WipSubsystem> cq = cb.createQuery(WipSubsystem.class);
Root<WipSubsystem> from = cq.from(WipSubsystem.class);
cq.where(cb.and(preparePredicatesSubsystems(cb, cq, from, deleted,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
includeHistory).toArray(new Predicate[0])));
cq.select(from);
if (orderBy != null) {
Expression<String> exp = orderBy(from, orderBy);
if (BooleanUtils.toBoolean(isAsc)) {
cq.orderBy(cb.asc(exp));
} else {
cq.orderBy(cb.desc(exp));
}
}
TypedQuery<WipSubsystem> query = em.createQuery(cq);
if (offset != null && limit != null) {
query.setFirstResult(offset * limit);
query.setMaxResults(limit);
}
return query.getResultList();
}
/**
* Prepare predicates for subsystems.
*
* @param cb criteria builder
* @param cq criteria query
* @param from criteria query root
* @param deleted deleted
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param includeHistory include history
* @return list of predicates
*/
private List<Predicate> preparePredicatesSubsystems(CriteriaBuilder cb, CriteriaQuery cq, Root<WipSubsystem> from, Boolean deleted,
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
Boolean includeHistory) {
List<Predicate> predicates = new ArrayList<>();
if (!Boolean.TRUE.equals(includeHistory)) {
// purpose of Naming to show valid entries
// therefore
// exclude some values unless history requested
// make sure to not exclude present and future values (latest approved and pending)
//
// condition(s)
// exclude content (with latest) before latest
// exclude content (with latest) after latest (cancelled, rejected)
// keep most recent content (without latest) (to have most recent in line of uuid without latest)
// <-->
// select * from structure s
// where (
// not (exists (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.id < (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true))
// and not (exists (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.id > (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.status in ('CANCELLED', 'REJECTED'))
// and not (not exists (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.id < (select max(s2.id) from structure s2 where s2."uuid" = s."uuid" and s2.latest=false))
// )
// <-->
// not (exists (subquery id) and s.id < (subquery id))
// and not (exists (subquery id) and s.id > (subquery id) and s.status in ('CANCELLED', 'REJECTED'))
// and not (not exists (subquery id) and s.id < (subquery 2))
//
// note
// persistence libraries may optimize query
// e.g. change (!a and !b) to !(a or b)
Subquery<Long> sub = cq.subquery(Long.class);
Root<WipSubsystem> fromSub = sub.from(WipSubsystem.class);
sub.where(cb.and(
cb.equal(fromSub.get(WipNameStructure.FIELD_UUID), from.get(WipNameStructure.FIELD_UUID)),
cb.equal(fromSub.get(WipNameStructure.FIELD_LATEST), Boolean.TRUE)
));
sub.select(fromSub.get(Persistable.FIELD_ID));
Subquery<Long> sub2 = cq.subquery(Long.class);
Root<WipSubsystem> fromSub2 = sub2.from(WipSubsystem.class);
sub2.where(cb.and(
cb.equal(fromSub2.get(WipNameStructure.FIELD_UUID), from.get(WipNameStructure.FIELD_UUID)),
cb.equal(fromSub2.get(WipNameStructure.FIELD_LATEST), Boolean.FALSE)
));
sub2.select(cb.max(fromSub2.get(Persistable.FIELD_ID)));
Predicate predicateExclude =
cb.and(
cb.not(cb.and(
cb.exists(sub),
cb.lessThan(from.get(Persistable.FIELD_ID).as(Long.class), sub))),
cb.not(cb.and(
cb.exists(sub),
cb.greaterThan(from.get(Persistable.FIELD_ID).as(Long.class), sub),
cb.or(
cb.equal(from.get(WipNameStructure.FIELD_STATUS), Status.CANCELLED),
cb.equal(from.get(WipNameStructure.FIELD_STATUS), Status.REJECTED)))),
cb.not(cb.and(
cb.not(cb.exists(sub)),
cb.lessThan(from.get(Persistable.FIELD_ID).as(Long.class), sub2)))
);
predicates.add(predicateExclude);
}
if (deleted != null) {
predicates.add(cb.equal(from.get(WipNameStructure.FIELD_DELETED), deleted));
}
// prepare pattern
// jpa query characters % and _
// remove excess % characters
if (!StringUtils.isEmpty(uuid)) {
predicates.add(cb.and(cb.equal(from.get(WipNameStructure.FIELD_UUID), RepositoryUtil.preparePattern(uuid))));
}
if (!StringUtils.isEmpty(parentUuid)) {
predicates.add(cb.and(cb.equal(from.get(WipSubsystem.FIELD_PARENT_UUID), RepositoryUtil.preparePattern(parentUuid))));
}
if (!StringUtils.isEmpty(mnemonic)) {
predicates.add(cb.and(cb.like(from.get(WipStructure.FIELD_MNEMONIC), RepositoryUtil.preparePattern(mnemonic))));
}
if (!StringUtils.isEmpty(mnemonicEquivalence)) {
predicates.add(cb.and(cb.like(from.get(WipStructure.FIELD_MNEMONIC_EQUIVALENCE), RepositoryUtil.preparePattern(mnemonicEquivalence))));
}
if (!StringUtils.isEmpty(mnemonicPath)) {
predicates.add(cb.and(cb.like(cb.function(WipSubsystem.FUNCTION_GET_MNEMONIC_PATH_SUBSYSTEM, String.class, from.get(WipNameStructure.FIELD_UUID)), RepositoryUtil.preparePattern(mnemonicPath))));
}
if (!StringUtils.isEmpty(description)) {
predicates.add(cb.and(cb.like(from.get(WipNameStructure.FIELD_DESCRIPTION), RepositoryUtil.preparePattern(description))));
}
if (!StringUtils.isEmpty(who)) {
predicates.add(cb.and(cb.like(from.get(WipNameStructure.FIELD_PROCESSED_BY), RepositoryUtil.preparePattern(who))));
}
return predicates;
}
/**
* Prepare order by query expression.
*
* @param root root type in the from clause
* @param orderBy field on which to order by
* @return order by query expression
*/
private Expression<String> orderBy(Root<WipSubsystem> root, FieldStructure orderBy) {
if (FieldStructure.UUID.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_UUID);
} else if (FieldStructure.PARENT.equals(orderBy)) {
return root.get(WipSubsystem.FIELD_PARENT_UUID);
} else if (FieldStructure.MNEMONIC.equals(orderBy)) {
return root.get(WipStructure.FIELD_MNEMONIC);
} else if (FieldStructure.MNEMONICPATH.equals(orderBy)) {
return root.get(WipStructure.FIELD_MNEMONIC);
} else if (FieldStructure.ORDERING.equals(orderBy)) {
return root.get(WipStructure.FIELD_ORDERING);
} else if (FieldStructure.DESCRIPTION.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_DESCRIPTION);
} else if (FieldStructure.WHEN.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_PROCESSED);
} else {
return root.get(WipStructure.FIELD_MNEMONIC);
}
}
/**
* Count subsystems history.
*
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @return count of subsystems
*/
public Long countSubsystemsHistory(
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who) {
// note
// use of function for mnemonic path
// deleted - null
// includeHistory - true
// where
// queryFields, queryValues
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<WipSubsystem> from = cq.from(WipSubsystem.class);
Subquery<String> sub = cq.subquery(String.class);
Root<WipSubsystem> fromSub = sub.from(WipSubsystem.class);
sub.where(cb.and(preparePredicatesSubsystems(cb, cq, fromSub, null,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
Boolean.TRUE).toArray(new Predicate[0])));
sub.select(fromSub.get(WipNameStructure.FIELD_UUID));
cq.where(cb.and(cb.in(from.get(WipNameStructure.FIELD_UUID)).value(sub)));
cq.select(cb.count(from));
return em.createQuery(cq).getSingleResult();
}
/**
* Find subsystems history.
*
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param orderBy order by
* @param isAsc is ascending
* @return list of subsystems
*/
public List<WipSubsystem> readSubsystemsHistory(
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
FieldStructure orderBy, Boolean isAsc) {
// note
// use of function for mnemonic path
// deleted - null
// includeHistory - true
// where
// queryFields, queryValues
// order
// orderBy, isAsc
// paging
// outside of method
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<WipSubsystem> cq = cb.createQuery(WipSubsystem.class);
Root<WipSubsystem> from = cq.from(WipSubsystem.class);
Subquery<String> sub = cq.subquery(String.class);
Root<WipSubsystem> fromSub = sub.from(WipSubsystem.class);
sub.where(cb.and(preparePredicatesSubsystems(cb, cq, fromSub, null,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
Boolean.TRUE).toArray(new Predicate[0])));
sub.select(fromSub.get(WipNameStructure.FIELD_UUID));
cq.where(cb.and(cb.in(from.get(WipNameStructure.FIELD_UUID)).value(sub)));
cq.select(from);
if (orderBy != null) {
Expression<String> exp = orderBy(from, orderBy);
if (BooleanUtils.toBoolean(isAsc)) {
cq.orderBy(cb.asc(exp));
} else {
cq.orderBy(cb.desc(exp));
}
}
return em.createQuery(cq).getResultList();
}
/**
* Persist subsystem into persistence context.
*
* @param subsystem subsystem
*/
public void createSubsystem(WipSubsystem subsystem) {
em.persist(subsystem);
}
/**
* Merge subsystem into persistence context.
*
* @param subsystem subsystem
*/
public void updateSubsystem(WipSubsystem subsystem) {
em.merge(subsystem);
}
}
/*
* Copyright (C) 2021 European Spallation Source ERIC.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.openepics.names.repository.wip;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.openepics.names.repository.model.Persistable;
import org.openepics.names.repository.model.wip.WipNameStructure;
import org.openepics.names.repository.model.wip.WipStructure;
import org.openepics.names.repository.model.wip.WipSystemGroup;
import org.openepics.names.rest.beans.FieldStructure;
import org.openepics.names.rest.beans.Status;
import org.openepics.names.util.RepositoryUtil;
import org.springframework.stereotype.Repository;
/**
* Handle system group information in JPA.
*
* @author Lars Johansson
*/
@Repository
public class WipSystemGroupRepository {
@PersistenceContext
private EntityManager em;
/**
* Count system groups.
*
* @param deleted deleted
* @param uuid uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param includeHistory include history
* @return count of system groups
*/
public Long countSystemGroups(Boolean deleted,
String uuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
Boolean includeHistory) {
// where
// deleted
// queryFields, queryValues
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<WipSystemGroup> from = cq.from(WipSystemGroup.class);
cq.where(cb.and(preparePredicatesSystemGroups(cb, cq, from, deleted,
uuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
includeHistory).toArray(new Predicate[0])));
cq.select(cb.count(from));
return em.createQuery(cq).getSingleResult();
}
/**
* Find system groups.
*
* @param deleted deleted
* @param uuid uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @return list of system groups
*/
public List<WipSystemGroup> readSystemGroups(Boolean deleted,
String uuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who) {
return readSystemGroups(deleted,
uuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
Boolean.FALSE, null, null, null, null);
}
/**
* Find system groups.
*
* @param deleted deleted
* @param uuid uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param includeHistory include history
* @param orderBy order by
* @param isAsc is ascending
* @param offset offset
* @param limit limit
* @return list of system groups
*/
public List<WipSystemGroup> readSystemGroups(Boolean deleted,
String uuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
Boolean includeHistory, FieldStructure orderBy, Boolean isAsc, Integer offset, Integer limit) {
// where
// deleted
// queryFields, queryValues
// order
// orderBy, isAsc
// paging
// offset, limit
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<WipSystemGroup> cq = cb.createQuery(WipSystemGroup.class);
Root<WipSystemGroup> from = cq.from(WipSystemGroup.class);
cq.where(cb.and(preparePredicatesSystemGroups(cb, cq, from, deleted,
uuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
includeHistory).toArray(new Predicate[0])));
cq.select(from);
if (orderBy != null) {
Expression<String> exp = orderBy(from, orderBy);
if (BooleanUtils.toBoolean(isAsc)) {
cq.orderBy(cb.asc(exp));
} else {
cq.orderBy(cb.desc(exp));
}
}
TypedQuery<WipSystemGroup> query = em.createQuery(cq);
if (offset != null && limit != null) {
query.setFirstResult(offset * limit);
query.setMaxResults(limit);
}
return query.getResultList();
}
/**
* Prepare predicates for system groups.
*
* @param cb criteria builder
* @param cq criteria query
* @param from criteria query root
* @param deleted deleted
* @param uuid uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param includeHistory include history
* @return list of predicates
*/
private List<Predicate> preparePredicatesSystemGroups(CriteriaBuilder cb, CriteriaQuery cq, Root<WipSystemGroup> from, Boolean deleted,
String uuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
Boolean includeHistory) {
List<Predicate> predicates = new ArrayList<>();
if (!Boolean.TRUE.equals(includeHistory)) {
// purpose of Naming to show valid entries
// therefore
// exclude obsolete values unless history requested
// make sure to not exclude present and future values (latest approved and pending)
//
// condition(s)
// exclude content (with latest) before latest
// exclude content (with latest) after latest (cancelled, rejected)
// keep most recent content (without latest) (to have most recent in line of uuid without latest)
// <-->
// select * from structure s
// where (
// not (exists (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.id < (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true))
// and not (exists (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.id > (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.status in ('CANCELLED', 'REJECTED'))
// and not (not exists (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.id < (select max(s2.id) from structure s2 where s2."uuid" = s."uuid" and s2.latest=false))
// )
// <-->
// not (exists (subquery id) and s.id < (subquery id))
// and not (exists (subquery id) and s.id > (subquery id) and s.status in ('CANCELLED', 'REJECTED'))
// and not (not exists (subquery id) and s.id < (subquery 2))
//
// note
// persistence libraries may optimize query
// e.g. change (!a and !b) to !(a or b)
Subquery<Long> sub = cq.subquery(Long.class);
Root<WipSystemGroup> fromSub = sub.from(WipSystemGroup.class);
sub.where(cb.and(
cb.equal(fromSub.get(WipNameStructure.FIELD_UUID), from.get(WipNameStructure.FIELD_UUID)),
cb.equal(fromSub.get(WipNameStructure.FIELD_LATEST), Boolean.TRUE)
));
sub.select(fromSub.get(Persistable.FIELD_ID));
Subquery<Long> sub2 = cq.subquery(Long.class);
Root<WipSystemGroup> fromSub2 = sub2.from(WipSystemGroup.class);
sub2.where(cb.and(
cb.equal(fromSub2.get(WipNameStructure.FIELD_UUID), from.get(WipNameStructure.FIELD_UUID)),
cb.equal(fromSub2.get(WipNameStructure.FIELD_LATEST), Boolean.FALSE)
));
sub2.select(cb.max(fromSub2.get(Persistable.FIELD_ID)));
Predicate predicateExclude =
cb.and(
cb.not(cb.and(
cb.exists(sub),
cb.lessThan(from.get(Persistable.FIELD_ID).as(Long.class), sub))),
cb.not(cb.and(
cb.exists(sub),
cb.greaterThan(from.get(Persistable.FIELD_ID).as(Long.class), sub),
cb.or(
cb.equal(from.get(WipNameStructure.FIELD_STATUS), Status.CANCELLED),
cb.equal(from.get(WipNameStructure.FIELD_STATUS), Status.REJECTED)))),
cb.not(cb.and(
cb.not(cb.exists(sub)),
cb.lessThan(from.get(Persistable.FIELD_ID).as(Long.class), sub2)))
);
predicates.add(predicateExclude);
}
if (deleted != null) {
predicates.add(cb.equal(from.get(WipNameStructure.FIELD_DELETED), deleted));
}
// prepare pattern
// jpa query characters % and _
// remove excess % characters
if (!StringUtils.isEmpty(uuid)) {
predicates.add(cb.and(cb.equal(from.get(WipNameStructure.FIELD_UUID), RepositoryUtil.preparePattern(uuid))));
}
if (!StringUtils.isEmpty(mnemonic)) {
predicates.add(cb.and(cb.like(from.get(WipStructure.FIELD_MNEMONIC), RepositoryUtil.preparePattern(mnemonic))));
}
if (!StringUtils.isEmpty(mnemonicEquivalence)) {
predicates.add(cb.and(cb.like(from.get(WipStructure.FIELD_MNEMONIC_EQUIVALENCE), RepositoryUtil.preparePattern(mnemonicEquivalence))));
}
if (!StringUtils.isEmpty(mnemonicPath)) {
predicates.add(cb.and(cb.like(from.get(WipStructure.FIELD_MNEMONIC), RepositoryUtil.preparePattern(mnemonicPath))));
}
if (!StringUtils.isEmpty(description)) {
predicates.add(cb.and(cb.like(from.get(WipNameStructure.FIELD_DESCRIPTION), RepositoryUtil.preparePattern(description))));
}
if (!StringUtils.isEmpty(who)) {
predicates.add(cb.and(cb.like(from.get(WipNameStructure.FIELD_PROCESSED_BY), RepositoryUtil.preparePattern(who))));
}
return predicates;
}
/**
* Prepare order by query expression.
*
* @param root root type in the from clause
* @param orderBy field on which to order by
* @return order by query expression
*/
private Expression<String> orderBy(Root<WipSystemGroup> root, FieldStructure orderBy) {
// no parent for system group
if (FieldStructure.UUID.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_UUID);
} else if (FieldStructure.MNEMONIC.equals(orderBy)) {
return root.get(WipStructure.FIELD_MNEMONIC);
} else if (FieldStructure.MNEMONICPATH.equals(orderBy)) {
return root.get(WipStructure.FIELD_MNEMONIC);
} else if (FieldStructure.ORDERING.equals(orderBy)) {
return root.get(WipStructure.FIELD_ORDERING);
} else if (FieldStructure.DESCRIPTION.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_DESCRIPTION);
} else if (FieldStructure.WHEN.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_PROCESSED);
} else {
return root.get(WipStructure.FIELD_MNEMONIC);
}
}
/**
* Count system groups history.
*
* @param uuid uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @return count of system groups
*/
public Long countSystemGroupsHistory(
String uuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who) {
// note
// deleted - null
// includeHistory - true
// where
// queryFields, queryValues
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<WipSystemGroup> from = cq.from(WipSystemGroup.class);
Subquery<String> sub = cq.subquery(String.class);
Root<WipSystemGroup> fromSub = sub.from(WipSystemGroup.class);
sub.where(cb.and(preparePredicatesSystemGroups(cb, cq, fromSub, null,
uuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
Boolean.TRUE).toArray(new Predicate[0])));
sub.select(fromSub.get(WipNameStructure.FIELD_UUID));
cq.where(cb.and(cb.in(from.get(WipNameStructure.FIELD_UUID)).value(sub)));
cq.select(cb.count(from));
return em.createQuery(cq).getSingleResult();
}
/**
* Find system groups history.
*
* @param uuid uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param orderBy order by
* @param isAsc is ascending
* @return list of system groups
*/
public List<WipSystemGroup> readSystemGroupsHistory(
String uuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
FieldStructure orderBy, Boolean isAsc) {
// note
// deleted - null
// includeHistory - true
// where
// queryFields, queryValues
// order
// orderBy, isAsc
// paging
// outside of method
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<WipSystemGroup> cq = cb.createQuery(WipSystemGroup.class);
Root<WipSystemGroup> from = cq.from(WipSystemGroup.class);
Subquery<String> sub = cq.subquery(String.class);
Root<WipSystemGroup> fromSub = sub.from(WipSystemGroup.class);
sub.where(cb.and(preparePredicatesSystemGroups(cb, cq, fromSub, null,
uuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
Boolean.TRUE).toArray(new Predicate[0])));
sub.select(fromSub.get(WipNameStructure.FIELD_UUID));
cq.where(cb.and(cb.in(from.get(WipNameStructure.FIELD_UUID)).value(sub)));
cq.select(from);
if (orderBy != null) {
Expression<String> exp = orderBy(from, orderBy);
if (BooleanUtils.toBoolean(isAsc)) {
cq.orderBy(cb.asc(exp));
} else {
cq.orderBy(cb.desc(exp));
}
}
return em.createQuery(cq).getResultList();
}
/**
* Persist system group into persistence context.
*
* @param systemGroup system group
*/
public void createSystemGroup(WipSystemGroup systemGroup) {
em.persist(systemGroup);
}
/**
* Merge system group into persistence context.
*
* @param systemGroup system group
*/
public void updateSystemGroup(WipSystemGroup systemGroup) {
em.merge(systemGroup);
}
}
/*
* Copyright (C) 2021 European Spallation Source ERIC.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.openepics.names.repository.wip;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.openepics.names.repository.model.Persistable;
import org.openepics.names.repository.model.wip.WipNameStructure;
import org.openepics.names.repository.model.wip.WipStructure;
import org.openepics.names.repository.model.wip.WipSystem;
import org.openepics.names.rest.beans.FieldStructure;
import org.openepics.names.rest.beans.Status;
import org.openepics.names.util.RepositoryUtil;
import org.springframework.stereotype.Repository;
/**
* Handle system information in JPA.
*
* @author Lars Johansson
*/
@Repository
public class WipSystemRepository {
@PersistenceContext
private EntityManager em;
/**
* Count systems.
*
* @param deleted deleted
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param includeHistory include history
* @return count of systems
*/
public Long countSystems(Boolean deleted,
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
Boolean includeHistory) {
// note
// use of function for mnemonic path
// where
// deleted
// queryFields, queryValues
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<WipSystem> from = cq.from(WipSystem.class);
cq.where(cb.and(preparePredicatesSystems(cb, cq, from, deleted,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
includeHistory).toArray(new Predicate[0])));
cq.select(cb.count(from));
return em.createQuery(cq).getSingleResult();
}
/**
* Find systems.
*
* @param deleted deleted
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @return list of systems
*/
public List<WipSystem> readSystems(Boolean deleted,
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who) {
return readSystems(deleted,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
Boolean.FALSE, null, null, null, null);
}
/**
* Find systems.
*
* @param deleted deleted
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param includeHistory include history
* @param orderBy order by
* @param isAsc is ascending
* @param offset offset
* @param limit limit
* @return list of systems
*/
public List<WipSystem> readSystems(Boolean deleted,
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
Boolean includeHistory, FieldStructure orderBy, Boolean isAsc, Integer offset, Integer limit) {
// note
// use of function for mnemonic path
// where
// deleted
// queryFields, queryValues
// order
// orderBy, isAsc
// paging
// offset, limit
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<WipSystem> cq = cb.createQuery(WipSystem.class);
Root<WipSystem> from = cq.from(WipSystem.class);
cq.where(cb.and(preparePredicatesSystems(cb, cq, from, deleted,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
includeHistory).toArray(new Predicate[0])));
cq.select(from);
if (orderBy != null) {
Expression<String> exp = orderBy(from, orderBy);
if (BooleanUtils.toBoolean(isAsc)) {
cq.orderBy(cb.asc(exp));
} else {
cq.orderBy(cb.desc(exp));
}
}
TypedQuery<WipSystem> query = em.createQuery(cq);
if (offset != null && limit != null) {
query.setFirstResult(offset * limit);
query.setMaxResults(limit);
}
return query.getResultList();
}
/**
* Prepare predicates for systems.
*
* @param cb criteria builder
* @param cq criteria query
* @param from criteria query root
* @param deleted deleted
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param includeHistory include history
* @return list of predicates
*/
private List<Predicate> preparePredicatesSystems(CriteriaBuilder cb, CriteriaQuery cq, Root<WipSystem> from, Boolean deleted,
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
Boolean includeHistory) {
List<Predicate> predicates = new ArrayList<>();
if (!Boolean.TRUE.equals(includeHistory)) {
// purpose of Naming to show valid entries
// therefore
// exclude some values unless history requested
// make sure to not exclude present and future values (latest approved and pending)
//
// condition(s)
// exclude content (with latest) before latest
// exclude content (with latest) after latest (cancelled, rejected)
// keep most recent content (without latest) (to have most recent in line of uuid without latest)
// <-->
// select * from structure s
// where (
// not (exists (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.id < (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true))
// and not (exists (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.id > (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.status in ('CANCELLED', 'REJECTED'))
// and not (not exists (select s2.id from structure s2 where s2."uuid" = s."uuid" and s2.latest=true) and s.id < (select max(s2.id) from structure s2 where s2."uuid" = s."uuid" and s2.latest=false))
// )
// <-->
// not (exists (subquery id) and s.id < (subquery id))
// and not (exists (subquery id) and s.id > (subquery id) and s.status in ('CANCELLED', 'REJECTED'))
// and not (not exists (subquery id) and s.id < (subquery 2))
//
// note
// persistence libraries may optimize query
// e.g. change (!a and !b) to !(a or b)
Subquery<Long> sub = cq.subquery(Long.class);
Root<WipSystem> fromSub = sub.from(WipSystem.class);
sub.where(cb.and(
cb.equal(fromSub.get(WipNameStructure.FIELD_UUID), from.get(WipNameStructure.FIELD_UUID)),
cb.equal(fromSub.get(WipNameStructure.FIELD_LATEST), Boolean.TRUE)
));
sub.select(fromSub.get(Persistable.FIELD_ID));
Subquery<Long> sub2 = cq.subquery(Long.class);
Root<WipSystem> fromSub2 = sub2.from(WipSystem.class);
sub2.where(cb.and(
cb.equal(fromSub2.get(WipNameStructure.FIELD_UUID), from.get(WipNameStructure.FIELD_UUID)),
cb.equal(fromSub2.get(WipNameStructure.FIELD_LATEST), Boolean.FALSE)
));
sub2.select(cb.max(fromSub2.get(Persistable.FIELD_ID)));
Predicate predicateExclude =
cb.and(
cb.not(cb.and(
cb.exists(sub),
cb.lessThan(from.get(Persistable.FIELD_ID).as(Long.class), sub))),
cb.not(cb.and(
cb.exists(sub),
cb.greaterThan(from.get(Persistable.FIELD_ID).as(Long.class), sub),
cb.or(
cb.equal(from.get(WipNameStructure.FIELD_STATUS), Status.CANCELLED),
cb.equal(from.get(WipNameStructure.FIELD_STATUS), Status.REJECTED)))),
cb.not(cb.and(
cb.not(cb.exists(sub)),
cb.lessThan(from.get(Persistable.FIELD_ID).as(Long.class), sub2)))
);
predicates.add(predicateExclude);
}
if (deleted != null) {
predicates.add(cb.equal(from.get(WipNameStructure.FIELD_DELETED), deleted));
}
// prepare pattern
// jpa query characters % and _
// remove excess % characters
if (!StringUtils.isEmpty(uuid)) {
predicates.add(cb.and(cb.equal(from.get(WipNameStructure.FIELD_UUID), RepositoryUtil.preparePattern(uuid))));
}
if (!StringUtils.isEmpty(parentUuid)) {
predicates.add(cb.and(cb.equal(from.get(WipSystem.FIELD_PARENT_UUID), RepositoryUtil.preparePattern(parentUuid))));
}
if (!StringUtils.isEmpty(mnemonic)) {
predicates.add(cb.and(cb.like(from.get(WipStructure.FIELD_MNEMONIC), RepositoryUtil.preparePattern(mnemonic))));
}
if (!StringUtils.isEmpty(mnemonicEquivalence)) {
predicates.add(cb.and(cb.like(from.get(WipStructure.FIELD_MNEMONIC_EQUIVALENCE), RepositoryUtil.preparePattern(mnemonicEquivalence))));
}
if (!StringUtils.isEmpty(mnemonicPath)) {
predicates.add(cb.and(cb.like(cb.function(WipSystem.FUNCTION_GET_MNEMONIC_PATH_SYSTEM, String.class, from.get(WipNameStructure.FIELD_UUID)), RepositoryUtil.preparePattern(mnemonicPath))));
}
if (!StringUtils.isEmpty(description)) {
predicates.add(cb.and(cb.like(from.get(WipNameStructure.FIELD_DESCRIPTION), RepositoryUtil.preparePattern(description))));
}
if (!StringUtils.isEmpty(who)) {
predicates.add(cb.and(cb.like(from.get(WipNameStructure.FIELD_PROCESSED_BY), RepositoryUtil.preparePattern(who))));
}
return predicates;
}
/**
* Prepare order by query expression.
*
* @param root root type in the from clause
* @param orderBy field on which to order by
* @return order by query expression
*/
private Expression<String> orderBy(Root<WipSystem> root, FieldStructure orderBy) {
if (FieldStructure.UUID.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_UUID);
} else if (FieldStructure.PARENT.equals(orderBy)) {
return root.get(WipSystem.FIELD_PARENT_UUID);
} else if (FieldStructure.MNEMONIC.equals(orderBy)) {
return root.get(WipStructure.FIELD_MNEMONIC);
} else if (FieldStructure.MNEMONICPATH.equals(orderBy)) {
return root.get(WipStructure.FIELD_MNEMONIC);
} else if (FieldStructure.ORDERING.equals(orderBy)) {
return root.get(WipStructure.FIELD_ORDERING);
} else if (FieldStructure.DESCRIPTION.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_DESCRIPTION);
} else if (FieldStructure.WHEN.equals(orderBy)) {
return root.get(WipNameStructure.FIELD_PROCESSED);
} else {
return root.get(WipStructure.FIELD_MNEMONIC);
}
}
/**
* Count systems history.
*
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @return count of systems
*/
public Long countSystemsHistory(
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who) {
// note
// use of function for mnemonic path
// deleted - null
// includeHistory - true
// where
// queryFields, queryValues
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<WipSystem> from = cq.from(WipSystem.class);
Subquery<String> sub = cq.subquery(String.class);
Root<WipSystem> fromSub = sub.from(WipSystem.class);
sub.where(cb.and(preparePredicatesSystems(cb, cq, fromSub, null,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
Boolean.TRUE).toArray(new Predicate[0])));
sub.select(fromSub.get(WipNameStructure.FIELD_UUID));
cq.where(cb.and(cb.in(from.get(WipNameStructure.FIELD_UUID)).value(sub)));
cq.select(cb.count(from));
return em.createQuery(cq).getSingleResult();
}
/**
* Find systems history.
*
* @param uuid uuid
* @param parentUuid parent uuid
* @param mnemonic mnemonic
* @param mnemonicEquivalence mnemonic equivalence
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param orderBy order by
* @param isAsc is ascending
* @return list of systems
*/
public List<WipSystem> readSystemsHistory(
String uuid, String parentUuid, String mnemonic, String mnemonicEquivalence, String mnemonicPath, String description, String who,
FieldStructure orderBy, Boolean isAsc) {
// note
// use of function for mnemonic path
// deleted - null
// includeHistory - true
// where
// queryFields, queryValues
// order
// orderBy, isAsc
// paging
// outside of method
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<WipSystem> cq = cb.createQuery(WipSystem.class);
Root<WipSystem> from = cq.from(WipSystem.class);
Subquery<String> sub = cq.subquery(String.class);
Root<WipSystem> fromSub = sub.from(WipSystem.class);
sub.where(cb.and(preparePredicatesSystems(cb, cq, fromSub, null,
uuid, parentUuid, mnemonic, mnemonicEquivalence, mnemonicPath, description, who,
Boolean.TRUE).toArray(new Predicate[0])));
sub.select(fromSub.get(WipNameStructure.FIELD_UUID));
cq.where(cb.and(cb.in(from.get(WipNameStructure.FIELD_UUID)).value(sub)));
cq.select(from);
if (orderBy != null) {
Expression<String> exp = orderBy(from, orderBy);
if (BooleanUtils.toBoolean(isAsc)) {
cq.orderBy(cb.asc(exp));
} else {
cq.orderBy(cb.desc(exp));
}
}
return em.createQuery(cq).getResultList();
}
/**
* Persist system into persistence context.
*
* @param system system
*/
public void createSystem(WipSystem system) {
em.persist(system);
}
/**
* Merge system into persistence context.
*
* @param system system
*/
public void updateSystem(WipSystem system) {
em.merge(system);
}
}
package org.openepics.names.rest.api.v1;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.openepics.names.exception.ServiceException;
import org.openepics.names.rest.beans.security.Login;
import org.openepics.names.rest.beans.security.LoginResponse;
import org.openepics.names.service.security.dto.UserDetails;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author <a href="mailto:zoltan.runyo@ess.eu">Zoltan Runyo</a>
*/
@RequestMapping("/api/v1/authentication")
@Tag(name = "5. Authentication")
public interface IAuthentication {
@Operation(
summary = "Login user and acquire JWT token",
description = "Login user with username, and password in order to acquire JWT token")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "Ok",
content = @Content(schema = @Schema(implementation = LoginResponse.class))),
@ApiResponse(
responseCode = "401",
description = "Bad username, and/or password",
content = @Content(schema = @Schema(implementation = ServiceException.class))),
@ApiResponse(
responseCode = "403",
description = "User doesn't have permission to log in",
content = @Content(schema = @Schema(implementation = ServiceException.class))),
@ApiResponse(
responseCode = "503",
description = "Login server unavailable",
content = @Content(schema = @Schema(implementation = ServiceException.class))),
@ApiResponse(
responseCode = "500",
description = "Service exception",
content = @Content(schema = @Schema(implementation = ServiceException.class)))
})
@PostMapping(
value = "/login",
produces = {"application/json"},
consumes = {"application/json"})
ResponseEntity<LoginResponse> login(@RequestBody Login loginInfo);
@Operation(
summary = "Renewing JWT token",
description = "Renewing valid, non-expired JWT token",
security = {@SecurityRequirement(name = "bearerAuth")})
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "Ok",
content = @Content(schema = @Schema(implementation = LoginResponse.class))),
@ApiResponse(
responseCode = "401",
description = "Unauthorized",
content = @Content(schema = @Schema(implementation = ServiceException.class))),
@ApiResponse(
responseCode = "403",
description = "Permission denied",
content = @Content(schema = @Schema(implementation = ServiceException.class))),
@ApiResponse(
responseCode = "503",
description = "Login server unavailable",
content = @Content(schema = @Schema(implementation = ServiceException.class))),
@ApiResponse(
responseCode = "500",
description = "Service exception",
content = @Content(schema = @Schema(implementation = ServiceException.class)))
})
@PostMapping(
value = "/renew",
produces = {"application/json"})
ResponseEntity<LoginResponse> tokenRenew(@AuthenticationPrincipal UserDetails user);
@Operation(
summary = "Logout",
description = "Logging out the user",
security = {@SecurityRequirement(name = "bearerAuth")})
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "Ok"),
@ApiResponse(
responseCode = "500",
description = "Service exception",
content = @Content(schema = @Schema(implementation = ServiceException.class))),
@ApiResponse(
responseCode = "503",
description = "Login server unavailable or remote error",
content = @Content(schema = @Schema(implementation = ServiceException.class)))
})
@DeleteMapping(
value = "/logout",
produces = {"application/json"})
ResponseEntity<Object> logout(@AuthenticationPrincipal UserDetails user);
}
/*
* Copyright (C) 2023 European Spallation Source ERIC.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.openepics.names.rest.api.v1;
import java.util.List;
import org.openepics.names.rest.beans.element.NameElement;
import org.openepics.names.rest.beans.element.StructureElement;
import org.openepics.names.rest.beans.response.Response;
import org.openepics.names.rest.beans.response.ResponseString;
import org.openepics.names.util.ExcelUtil;
import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
/**
* This part of REST API provides conversion of names and structures data from one format to another, e.g. Excel to Json, for Naming application.
*
* @author Lars Johansson
*/
@Tag(name = "4. Convert",
description = "handle conversion of names and structures data from one format to another for Naming application")
@RequestMapping("/api/v1/convert")
public interface IConvert {
/*
NameElementCommand - encompasses
NameElementCommandCreate
NameElementCommandUpdate
NameElementCommandConfirm
----------------------------------------------------------------------------------------------------
StructureElementCommand - encompasses
StructureElementCommandCreate
StructureElementCommandUpdate
StructureElementCommandConfirm
Methods
read POST /excel2Json/names - convertExcel2JsonNames
read POST /excel2Json/structures - convertExcel2JsonStructures
----------------------------------------------------------------------------------------------------
read POST /json2Excel/names - convertJson2ExcelNames
read POST /json2Excel/structures - convertJson2ExcelStructures
*/
/**
* Convert names data in Excel file to json.
* Expected columns as in Excel template for names.
* This endpoint is for conversion of content in Excel to be able to send it to Naming application as json.
*
* @param file Excel file according to template for names
* @return json that corresponds to rows in Excel file
*/
@Operation(
summary = "Convert names data in Excel file to json",
description = """
Convert names data in Excel file to json.
Expected columns as in Excel template for names.
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Response contains json equivalent to content in Excel file.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseString.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@PostMapping(
value = "/excel2Json/names",
produces = {"application/json"},
consumes = {"multipart/form-data"})
public ResponseEntity<ResponseString> convertExcel2JsonNames(
@Parameter(
in = ParameterIn.DEFAULT,
description = "Excel file according to template for names",
content = @Content(mediaType = ExcelUtil.MIME_TYPE_OPENXML_SPREADSHEET),
required = true)
@RequestParam("file") MultipartFile file);
/**
* Convert structures data in Excel file to json.
* Expected columns as in Excel template for structures.
* This endpoint is for conversion of content in Excel to be able to send it to Naming application as json.
*
* @param file Excel file according to template for structures
* @return json that corresponds to rows in Excel file
*/
@Operation(
summary = "Convert structures data in Excel file to json",
description = """
Convert structures data in Excel file to json.
Expected columns as in Excel template for structures.
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Response contains json equivalent to content in Excel file.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseString.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@PostMapping(
value = "/excel2Json/structures",
produces = {"application/json"},
consumes = {"multipart/form-data"})
public ResponseEntity<ResponseString> convertExcel2JsonStructures(
@Parameter(
in = ParameterIn.DEFAULT,
description = "Excel file according to template for structures",
content = @Content(mediaType = ExcelUtil.MIME_TYPE_OPENXML_SPREADSHEET),
required = true)
@RequestParam("file") MultipartFile file);
// ----------------------------------------------------------------------------------------------------
/**
* Convert names data in json to Excel file.
* Expected content for json like result for names query.
*
* @param json json like result for names query - array of name elements
* @return Excel file
*/
@Operation(
summary = "Convert names data in json to Excel file",
description = """
Convert names data in json to Excel file.
Expected content for json like result for names query.
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Response contains Excel file with content equivalent to json.",
content = @Content(mediaType = ExcelUtil.MIME_TYPE_EXCEL)),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@PostMapping(
value = "/json2Excel/names",
produces = {"application/vnd.ms-excel"},
consumes = {"application/json"})
public ResponseEntity<Resource> convertJson2ExcelNames(
@Parameter(
in = ParameterIn.DEFAULT,
description = "test json",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = NameElement.class))))
@RequestBody List<NameElement> nameElements);
/**
* Convert structures data in json to Excel file.
* Expected content for json like result for structures query.
*
* @param json json like result for names query - array of structure elements
* @return Excel file
*/
@Operation(
summary = "Convert structures data in json to Excel file",
description = """
Convert structures data in json to Excel file.
Expected content for json like result for structures query.
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Response contains Excel file with content equivalent to json.",
content = @Content(mediaType = ExcelUtil.MIME_TYPE_EXCEL)),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@PostMapping(
value = "/json2Excel/structures",
produces = {"application/vnd.ms-excel"},
consumes = {"application/json"})
public ResponseEntity<Resource> convertJson2ExcelStructures(
@Parameter(
in = ParameterIn.DEFAULT,
description = "test json",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = StructureElement.class))))
@RequestBody List<StructureElement> structureElements);
}
......@@ -20,16 +20,20 @@ package org.openepics.names.rest.api.v1;
import java.util.List;
import org.openepics.names.configuration.SecurityConfiguration;
import org.openepics.names.rest.beans.FieldName;
import org.openepics.names.rest.beans.element.NameElement;
import org.openepics.names.rest.beans.element.NameElementCommand;
import org.openepics.names.rest.beans.element.NameElementCommandConfirm;
import org.openepics.names.rest.beans.element.NameElementCommandCreate;
import org.openepics.names.rest.beans.element.NameElementCommandUpdate;
import org.openepics.names.rest.beans.response.Response;
import org.openepics.names.rest.beans.response.ResponseBoolean;
import org.openepics.names.rest.beans.response.ResponseBooleanList;
import org.openepics.names.rest.beans.response.ResponsePageNameElements;
import org.openepics.names.util.ExcelUtil;
import org.springframework.core.io.Resource;
import org.openepics.names.service.security.dto.UserDetails;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
......@@ -38,7 +42,6 @@ import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
......@@ -49,6 +52,7 @@ import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
/**
......@@ -56,97 +60,95 @@ import io.swagger.v3.oas.annotations.tags.Tag;
*
* @author Lars Johansson
*/
@Tag(name = "Names",
@Tag(name = "1. Names",
description = "handle names data for Naming application")
@RequestMapping("/api/v1/names")
public interface INames {
/*
FieldName - UUID, NAME, NAMEEQUIVALENCE, SYSTEMSTRUCTURE, DEVICESTRUCTURE, DESCRIPTION
NameElementCommand - subset of NameElement attributes
NameElementCommandCreate - parentSystemStructure, parentDeviceStructure, index, description
NameElementCommandUpdate - uuid, parentSystemStructure, parentDeviceStructure, index, description
NameElementCommandConfirm - uuid
----------------------------------------------------------------------------------------------------
converted into NameElementCommand
----------------------------------------------------------------------------------------------------
NameElementCommand - uuid, parentSystemStructure, parentDeviceStructure, index, description
NameElement
uuid (UUID)
parentsystemstructure (UUID)
parentdevicestructure (UUID)
parentSystemStructure (UUID)
parentDeviceStructure (UUID)
index (String)
description (String)
comment (String)
----------------------------------
systemstructure (String)
devicestructure (String)
systemStructure (String)
deviceStructure (String)
name (String)
status (Status)
latest (Boolean)
deleted (Boolean)
when (Date)
who (String)
authentication/authorization
3 levels - no, user, administrator
no - read
user - create, update, delete
( administrator )
comment (String)
Methods
create POST /names - createNames (List<NameElementCommand>)
create POST /names/upload - createNames (MultipartFile)
create POST /names - createNames
----------------------------------------------------------------------------------------------------
read GET /names - readNames (Boolean, String, String, String, String, String, String, FieldName, Boolean, Integer, Integer)
read GET /names/download - readNamesDownload (Boolean, String, String, String, String, String, String, FieldName, Boolean, Integer, Integer)
read GET /names/{name} - readNames (String, FieldName, Boolean, Integer, Integer)
read GET /names/systemstructure/{mnemonicpath} - readNamesSystemStructure (String, FieldName, Boolean, Integer, Integer)
read GET /names/devicestructure/{mnemonicpath} - readNamesDeviceStructure (String, FieldName, Boolean, Integer, Integer)
read GET /names/history/{uuid} - readNamesHistory (String, FieldName, Boolean, Integer, Integer)
read GET /names - readNames
read GET /names/{uuid} - readName
read GET /names/structure/{uuid} - readNamesStructure
read GET /names/history/{uuid} - readNamesHistory
----------------------------------------------------------------------------------------------------
read GET /names/equivalence/{name} - equivalenceName (String)
read GET /names/exists/{name} - existsName (String)
read GET /names/islegacy/{name} - isLegacyName (String)
read GET /names/isvalidtocreate/{name} - isValidToCreateName (String)
read GET /names/exists/{name} - existsName hidden from Swagger UI
read GET /names/isValidToCreate/{name} - isValidToCreateName hidden from Swagger UI
----------------------------------------------------------------------------------------------------
read GET /names/validatecreate - validateNamesCreate (List<NameElementCommand>)
read GET /names/validateupdate - validateNamesUpdate (List<NameElementCommand>)
read GET /names/validatedelete - validateNamesDelete (List<NameElementCommand>)
read GET /names/validateCreate - validateNamesCreate hidden from Swagger UI
read GET /names/validateUpdate - validateNamesUpdate hidden from Swagger UI
read GET /names/validateDelete - validateNamesDelete hidden from Swagger UI
----------------------------------------------------------------------------------------------------
update PUT /names - updateNames (List<NameElementCommand>)
update PUT /names/upload - updateNames (MultipartFile)
update PUT /names - updateNames
----------------------------------------------------------------------------------------------------
delete DELETE /names - deleteNames (List<NameElementCommand>)
delete DELETE /names/upload - deleteNames (MultipartFile)
delete DELETE /names - deleteNames
Note
read GET /names/{name} - both name and uuid (name - exact and search, uuid exact)
/upload and /download endpoints handle Excel files
authentication/authorization
3 levels - no, user, administrator
no - read
user - create, update, delete
( administrator )
default for read is to have lifecycle attributes unless query for specific resource or specific use case
status, deleted
*/
public static final String DEFAULT_PAGE = "0";
public static final String DEFAULT_PAGE_SIZE = "100";
public static final String DEFAULT_PAGE = "0";
public static final String DEFAULT_PAGE_SIZE = "100";
public static final String DEFAULT_SORT_FIELD_WHEN = "WHEN";
public static final String DEFAULT_SORT_ORDER_ASC = "true";
/**
* Create names by list of name element commands.
* Create names by list of name elements.
* Return list of name elements for created names.
*
* @param nameElements list of name element commands
* @return list of created name elements
* @param nameElementCommands list of name elements
* @return list of name elements for created names
*/
@Operation(
summary = "Create names by array of name element commands",
summary = "Create names by array of name elements",
description = """
Create names by array of name element commands.
Create names by array of name elements.
Return array of name elements for created names.
Required attributes:
- parentsystemstructure (uuid)
- parentSystemStructure
- description
- comment
Optional attributes:
- parentdevicestructure (uuid)
- parentDeviceStructure
- index
Uuid is created by Naming.
"""
)
Note
- Uuid is created by Naming
""",
security = {@SecurityRequirement(name = "bearerAuth")})
@ApiResponses(value = {
@ApiResponse(
responseCode = "201",
......@@ -157,395 +159,205 @@ public interface INames {
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "401",
description = "Unauthorized. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "403",
description = "Forbidden. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "404",
description = "Not Found. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@PostMapping(
produces = {"application/json"},
consumes = {"application/json"})
@PreAuthorize(SecurityConfiguration.IS_ADMINISTRATOR_OR_USER)
public ResponseEntity<List<NameElement>> createNames(
@AuthenticationPrincipal UserDetails user,
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of name element commands",
required = true,
description = "array of name elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = NameElementCommand.class,
requiredProperties = {"parentsystemstructure","parentdevicestructure","index","description","comment"}))))
@RequestBody List<NameElementCommand> nameElements);
/**
* Create names by upload Excel file.
* Return Excel file with name elements for created names.
*
* @param file file
* @return Excel file
*/
@Operation(
summary = "Create names by upload Excel file",
description = """
Create names by upload Excel file.
Return Excel file with name elements for created names.
Expected columns as in Excel template for names.
Required attributes:
- parentsystemstructure (uuid)
- description
- comment
Optional attributes:
- parentdevicestructure (uuid)
- index
Uuid is created by Naming.
"""
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "201",
description = "OK. Return Excel file with name elements for created names.",
content = @Content(mediaType = ExcelUtil.MIME_TYPE_EXCEL)),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@PostMapping(
value = "/upload",
produces = {"application/vnd.ms-excel"},
consumes = {"multipart/form-data"})
public ResponseEntity<Resource> createNames(
@Parameter(
in = ParameterIn.DEFAULT,
description = "Excel file with name element commands",
required = true,
content = @Content(mediaType = ExcelUtil.MIME_TYPE_OPENXML_SPREADSHEET))
@RequestParam("file") MultipartFile file);
implementation = NameElementCommandCreate.class,
requiredProperties = {"parentSystemStructure","description"}))),
required = true)
@RequestBody List<NameElementCommandCreate> nameElementCommands);
// ----------------------------------------------------------------------------------------------------
/**
* Find valid names (search).
* Return paged list of name elements.
* Return list of name elements.
* Use deleted (false) to query for active names.
*
* @param deleted if deleted-only names are to be included
* (false for non-deleted-only names, true for deleted-only names, not used for both cases)
* @param uuid uuid
* @param deleted if deleted names are to be selected or not, omitted for both deleted and non-deleted names
* (true for deleted names, false for non-deleted names, omitted for both deleted and non-deleted names)
* @param name name
* @param nameequivalence name equivalence
* @param systemstructure system structure mnemonic path
* @param devicestructure device structure mnemonic path
* @param systemStructure system structure mnemonic path
* @param deviceStructure device structure mnemonic path
* @param index index
* @param description description
* @param who who
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param page page starting from 0, offset
* @param pageSize page size, limit
* @return paged list of name elements
* @return list of name elements
*/
@Operation(
summary = "Find valid names (search)",
description = """
Find valid names (search).
Return paged array of name elements.
"""
)
Return array of name elements.
Use deleted (false) to query for active names.
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return paged array of name elements.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponsePageNameElements.class))),
description = "OK. Return array of name elements.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponsePageNameElements.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
produces = {"application/json"})
public ResponsePageNameElements readNames(
@Parameter(in = ParameterIn.QUERY, description = "if deleted names are to be included or not, omitted for both deleted and not deleted names") @RequestParam(required = false) Boolean deleted,
@Parameter(in = ParameterIn.QUERY, description = "search by uuid") @RequestParam(required = false) String uuid,
@Parameter(in = ParameterIn.QUERY, description = "if deleted names are to be selected or not, omitted for both deleted and non-deleted names") @RequestParam(required = false) Boolean deleted,
@Parameter(in = ParameterIn.QUERY, description = "search by name") @RequestParam(required = false) String name,
@Parameter(in = ParameterIn.QUERY, description = "search by name equivalence") @RequestParam(required = false) String nameequivalence,
@Parameter(in = ParameterIn.QUERY, description = "search by system structure mnemonic path") @RequestParam(required = false) String systemstructure,
@Parameter(in = ParameterIn.QUERY, description = "search by device structure mnemonic path") @RequestParam(required = false) String devicestructure,
@Parameter(in = ParameterIn.QUERY, description = "search by system structure mnemonic path") @RequestParam(required = false) String systemStructure,
@Parameter(in = ParameterIn.QUERY, description = "search by device structure mnemonic path") @RequestParam(required = false) String deviceStructure,
@Parameter(in = ParameterIn.QUERY, description = "search by index") @RequestParam(required = false) String index,
@Parameter(in = ParameterIn.QUERY, description = "search by description") @RequestParam(required = false) String description,
@Parameter(in = ParameterIn.QUERY, description = "search by who") @RequestParam(required = false) String who,
@Parameter(in = ParameterIn.QUERY, description = "order by field") @RequestParam(required = false) FieldName orderBy,
@Parameter(in = ParameterIn.QUERY, description = "sort order, ascending or descending") @RequestParam(required = false) Boolean isAsc,
@Parameter(in = ParameterIn.QUERY, description = "page starting from 0, offset") @RequestParam(required = false, defaultValue = DEFAULT_PAGE) Integer page,
@Parameter(in = ParameterIn.QUERY, description = "page size, limit") @RequestParam(required = false, defaultValue = DEFAULT_PAGE_SIZE) Integer pageSize);
/**
* Find valid names (search).
* Return Excel file with paged list of name elements.
* Find valid name by uuid (exact match).
* Return list of name elements.
*
* @param deleted if deleted-only names are to be included
* (false for non-deleted-only names, true for deleted-only names, not used for both cases)
* @param uuid uuid
* @param name name
* @param nameequivalence name equivalence
* @param systemstructure system structure mnemonic path
* @param devicestructure device structure mnemonic path
* @param index index
* @param description description
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param page page starting from 0, offset
* @param pageSize page size, limit
* @return Excel file
* @return list of name elements
*/
@Operation(
summary = "Find valid names (search) and download Excel file",
summary = "Find valid name by uuid (exact match)",
description = """
Find valid names (search).
Return Excel file with paged list of name elements.
"""
)
Find valid name by uuid (exact match).
Return array of name elements.
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return Excel file with paged list of name elements.",
content = @Content(mediaType = ExcelUtil.MIME_TYPE_EXCEL)),
description = "OK. Return array of name elements.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponsePageNameElements.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/download",
produces = {"application/vnd.ms-excel"})
public ResponseEntity<Resource> readNamesDownload(
@Parameter(in = ParameterIn.QUERY, description = "if deleted names are to be included or not, omitted for both deleted and not deleted names") @RequestParam(required = false) Boolean deleted,
@Parameter(in = ParameterIn.QUERY, description = "search by uuid") @RequestParam(required = false) String uuid,
@Parameter(in = ParameterIn.QUERY, description = "search by name") @RequestParam(required = false) String name,
@Parameter(in = ParameterIn.QUERY, description = "search by name equivalence") @RequestParam(required = false) String nameequivalence,
@Parameter(in = ParameterIn.QUERY, description = "search by system structure mnemonic path") @RequestParam(required = false) String systemstructure,
@Parameter(in = ParameterIn.QUERY, description = "search by device structure mnemonic path") @RequestParam(required = false) String devicestructure,
@Parameter(in = ParameterIn.QUERY, description = "search by index") @RequestParam(required = false) String index,
@Parameter(in = ParameterIn.QUERY, description = "search by description") @RequestParam(required = false) String description,
@Parameter(in = ParameterIn.QUERY, description = "order by field") @RequestParam(required = false) FieldName orderBy,
@Parameter(in = ParameterIn.QUERY, description = "sort order, ascending or descending") @RequestParam(required = false) Boolean isAsc,
@Parameter(in = ParameterIn.QUERY, description = "page starting from 0, offset") @RequestParam(required = false, defaultValue = DEFAULT_PAGE) Integer page,
@Parameter(in = ParameterIn.QUERY, description = "page size, limit") @RequestParam(required = false, defaultValue = DEFAULT_PAGE_SIZE) Integer pageSize);
/**
* Find valid names by name or uuid (search).
* Return paged list of name elements.
*
* @param name name or uuid
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param page page starting from 0, offset
* @param pageSize page size, limit
* @return paged list of name elements
*/
@Operation(
summary = "Find valid names by name or uuid (search)",
description = """
Find valid names by name or uuid (search).
Return paged array of name elements.
"""
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return paged array of name elements.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponsePageNameElements.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
responseCode = "404",
description = "Not found. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/{name}",
value = "/{uuid}",
produces = {"application/json"})
public ResponsePageNameElements readNames(
@Parameter(in = ParameterIn.PATH, description = "search by name or uuid") @PathVariable("name") String name,
@Parameter(in = ParameterIn.QUERY, description = "order by field") @RequestParam(required = false) FieldName orderBy,
@Parameter(in = ParameterIn.QUERY, description = "sort order, ascending or descending") @RequestParam(required = false) Boolean isAsc,
@Parameter(in = ParameterIn.QUERY, description = "page starting from 0, offset") @RequestParam(required = false, defaultValue = DEFAULT_PAGE) Integer page,
@Parameter(in = ParameterIn.QUERY, description = "page size, limit") @RequestParam(required = false, defaultValue = DEFAULT_PAGE_SIZE) Integer pageSize);
public ResponseEntity<ResponsePageNameElements> readName(
@Parameter(in = ParameterIn.PATH, description = "find by uuid or name") @PathVariable("uuid") String uuid);
/**
* Find valid names by system structure mnemonic path (search).
* Return paged list of name elements.
* Find valid names by structure uuid that is referenced (exact match).
* Return list of name elements.
* Use deleted (false) to query for active names.
*
* @param mnemonicpath mnemonic path
* @param uuid uuid
* @param deleted if deleted names are to be selected or not, omitted for both deleted and non-deleted names
* (true for deleted names, false for non-deleted names, omitted for both deleted and non-deleted names)
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param page page starting from 0, offset
* @param pageSize page size, limit
* @return paged list of name elements
* @return list of name elements
*/
@Operation(
summary = "Find valid names by system structure mnemonic path (search)",
summary = "Find valid names by structure uuid that is referenced (exact match)",
description = """
Find valid names by system structure mnemonic path (search).
Return paged array of name elements.
"""
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return paged array of name elements.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponsePageNameElements.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/systemstructure/{mnemonicpath}",
produces = {"application/json"})
public ResponsePageNameElements readNamesSystemStructure(
@Parameter(in = ParameterIn.PATH, description = "search by system structure mnemonic path") @PathVariable("mnemonicpath") String mnemonicpath,
@Parameter(in = ParameterIn.QUERY, description = "order by field") @RequestParam(required = false) FieldName orderBy,
@Parameter(in = ParameterIn.QUERY, description = "sort order, ascending or descending") @RequestParam(required = false) Boolean isAsc,
@Parameter(in = ParameterIn.QUERY, description = "page starting from 0, offset") @RequestParam(required = false, defaultValue = DEFAULT_PAGE) Integer page,
@Parameter(in = ParameterIn.QUERY, description = "page size, limit") @RequestParam(required = false, defaultValue = DEFAULT_PAGE_SIZE) Integer pageSize);
Find valid names by structure uuid that is referenced (exact match).
Return list of name elements.
/**
* Find valid names by device structure mnemonic path (search).
* Return paged list of name elements.
*
* @param mnemonicpath mnemonic path
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param page page starting from 0, offset
* @param pageSize page size, limit
* @return paged list of name elements
*/
@Operation(
summary = "Find valid names by device structure mnemonic path (search)",
description = """
Find valid names by device structure mnemonic path (search).
Return paged array of name elements.
"""
)
Endpoint applies for any type of structure.
Use deleted (false) to query for active names.
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return paged array of name elements.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponsePageNameElements.class))),
description = "OK. Return array of name elements.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponsePageNameElements.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "404",
description = "Not found. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/devicestructure/{mnemonicpath}",
value = "/structure/{uuid}",
produces = {"application/json"})
public ResponsePageNameElements readNamesDeviceStructure(
@Parameter(in = ParameterIn.PATH, description = "search by device structure mnemonic path") @PathVariable("mnemonicpath") String mnemonicpath,
public ResponseEntity<ResponsePageNameElements> readNamesStructure(
@Parameter(in = ParameterIn.PATH, description = "find by structure uuid") @PathVariable("uuid") String uuid,
@Parameter(in = ParameterIn.QUERY, description = "if deleted names are to be selected or not, omitted for both deleted and non-deleted names") @RequestParam(required = false) Boolean deleted,
@Parameter(in = ParameterIn.QUERY, description = "order by field") @RequestParam(required = false) FieldName orderBy,
@Parameter(in = ParameterIn.QUERY, description = "sort order, ascending or descending") @RequestParam(required = false) Boolean isAsc,
@Parameter(in = ParameterIn.QUERY, description = "page starting from 0, offset") @RequestParam(required = false, defaultValue = DEFAULT_PAGE) Integer page,
......@@ -553,102 +365,54 @@ public interface INames {
/**
* Find history for name by uuid (exact match).
* Return paged list of name elements.
* Return list of name elements.
* History consists of line of uuid.
* The line of uuid is not broken in retrieving history.
* If the uuid is found in a name entry, the entire line of uuid is returned.
*
* @param uuid uuid
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param page page starting from 0, offset
* @param pageSize page size, limit
* @return paged list of name elements
* @return list of name elements
*/
@Operation(
summary = "Find history for name by uuid (exact match)",
description = """
Find history for name by uuid (exact match).
Return paged array of name elements.
"""
)
Return array of name elements.
History consists of line of uuid.
The line of uuid is not broken in retrieving history.
If the uuid is found in a name entry, the entire line of uuid is returned.
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return paged array of name elements.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponsePageNameElements.class))),
description = "OK. Return array of name elements.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponsePageNameElements.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "404",
description = "Not found. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/history/{uuid}",
produces = {"application/json"})
public ResponsePageNameElements readNamesHistory(
@Parameter(in = ParameterIn.PATH, description = "search by uuid") @PathVariable("uuid") String uuid,
@Parameter(in = ParameterIn.QUERY, description = "order by field") @RequestParam(required = false) FieldName orderBy,
@Parameter(in = ParameterIn.QUERY, description = "sort order, ascending or descending") @RequestParam(required = false) Boolean isAsc,
@Parameter(in = ParameterIn.QUERY, description = "page starting from 0, offset") @RequestParam(required = false, defaultValue = DEFAULT_PAGE) Integer page,
@Parameter(in = ParameterIn.QUERY, description = "page size, limit") @RequestParam(required = false, defaultValue = DEFAULT_PAGE_SIZE) Integer pageSize);
public ResponseEntity<ResponsePageNameElements> readNamesHistory(
@Parameter(in = ParameterIn.PATH, description = "find by uuid") @PathVariable("uuid") String uuid);
// ----------------------------------------------------------------------------------------------------
/**
* Return name equivalence for name.
*
* @param name name to get name equivalence for
* @return name equivalence
*/
@Operation(
summary = "Return name equivalence for name",
description = "Return name equivalence for name."
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return name equivalence.",
content = @Content(
mediaType = "text/plain",
schema = @Schema(implementation = String.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/equivalence/{name}")
public String equivalenceName(
@Parameter(in = ParameterIn.PATH, description = "name to get name equivalence for") @PathVariable("name") String name);
/**
* Return if name exists (exact match).
*
......@@ -660,44 +424,22 @@ public interface INames {
* @param name name to check if it exists
* @return if name exists
*/
@Hidden
@Operation(
summary = "Return if name exists (exact match)",
description = "Return if name exists (exact match)."
)
description = """
Return if name exists (exact match).
Response is true if name exists, false otherwise.
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = """
OK. Response is true if name exists, false otherwise.
Message and details are available if no response is available.
""",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponseBoolean.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
description = "OK. Response is true if name exists, false otherwise.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBoolean.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/exists/{name}",
......@@ -705,66 +447,6 @@ public interface INames {
public ResponseEntity<ResponseBoolean> existsName(
@Parameter(in = ParameterIn.PATH, description = "name to check if it exists") @PathVariable("name") String name);
/**
* Return if name is legacy name (exact match).
* A name is considered legacy name if one or more of its parents is deleted.
*
* <p>
* Response is true if name is legacy name, false otherwise.
* Message and details are available if no response is available.
* </p>
*
* @param name name to check if it is legacy name
* @return if name is legacy name
*/
@Operation(
summary = "Return if name is legacy name (exact match)",
description = """
Return if name is legacy name (exact match).
A name is considered legacy name if one or more of its parents is deleted.
"""
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = """
OK. Response is true if name is legacy name, false otherwise.
Message and details are available if no response is available.
""",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponseBoolean.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "404",
description = "Not Found. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/islegacy/{name}",
produces = {"application/json"})
public ResponseEntity<ResponseBoolean> isLegacyName(
@Parameter(in = ParameterIn.PATH, description = "name to check if it is legacy name") @PathVariable("name") String name);
/**
* Return if name is valid to create (exact match).
* Method answers question 'would it be ok to create given name?'.
......@@ -777,44 +459,25 @@ public interface INames {
* @param name name to check if it is valid to create
* @return if name is valid to create
*/
@Hidden
@Operation(
summary = "Return if name is valid to create (exact match)",
description = """
Return if name is valid to create (exact match).
Method answers question 'would it be ok to create given name?'.
"""
)
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = """
OK. Response is true if name is valid to create, false otherwise.
Message and details are available if no response is available.
""",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponseBoolean.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
description = "OK. Response is true if name is valid to create, false otherwise.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBoolean.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/isvalidtocreate/{name}",
value = "/isValidToCreate/{name}",
produces = {"application/json"})
public ResponseEntity<ResponseBoolean> isValidToCreateName(
@Parameter(in = ParameterIn.PATH, description = "name to check if it is valid to create") @PathVariable("name") String name);
......@@ -822,92 +485,76 @@ public interface INames {
// ----------------------------------------------------------------------------------------------------
/**
* Return if names are valid to create by list of name element commands.
* Return if names are valid to create by list of name elements.
* If names are valid to create, successful create of names can be expected.
*
* <p>
* Response is true if all name element commands validated ok, false otherwise, responses contain array
* with result for each name element command. Message and details are available if no response is available.
* Response is true if all name elements validated ok, false otherwise, responses contain array
* with result for each name element. Message and details are available if no response is available.
* </p>
*
* @param nameElements list of name element commands
* @param nameElementCommands list of name elements
* @return if list of names is valid to create
*/
@Hidden
@Operation(
summary = "Return if names are valid to create by list of name element commands",
summary = "Return if names are valid to create by list of name elements",
description = """
Return if names are valid to create by list of name element commands.
Return if names are valid to create by list of name elements.
If names are valid to create, successful create of names can be expected.
Required attributes:
- parentsystemstructure (uuid)
- parentSystemStructure
- description
- comment
Optional attributes:
- parentdevicestructure (uuid)
- parentDeviceStructure
- index
Uuid is created by Naming.
"""
)
Note
- Uuid is created by Naming
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = """
OK. Response is true if all name element commands validated ok, false otherwise.
Responses contain array with result for each name element command. Message and details are available if no response is available.
""",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponseBooleanList.class))),
description = "OK. Response is true if all name elements validated ok, false otherwise. Responses contain array with result for each name element.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBooleanList.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/validatecreate",
value = "/validateCreate",
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<ResponseBooleanList> validateNamesCreate(
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of name element commands",
required = true,
description = "array of name elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = NameElementCommand.class,
requiredProperties = {"parentsystemstructure","parentdevicestructure","index","description","comment"}))))
@RequestBody List<NameElementCommand> nameElements);
implementation = NameElementCommandCreate.class,
requiredProperties = {"parentSystemStructure","parentDeviceStructure","index","description"}))),
required = true)
@RequestBody List<NameElementCommandCreate> nameElementCommands);
/**
* Return if names are valid to update by list of name element commands.
* Return if names are valid to update by list of name elements.
* If names are valid to update, successful update of names can be expected.
*
* <p>
* Response is true if all name element commands validated ok, false otherwise, responses contain array
* with result for each name element command. Message and details are available if no response is available.
* Response is true if all name elements validated ok, false otherwise, responses contain array
* with result for each name element. Message and details are available if no response is available.
* </p>
*
* @param nameElements list of name element commands
* @param nameElementCommands list of name elements
* @return if list of name elements is valid to update
*/
@Hidden
......@@ -919,159 +566,122 @@ public interface INames {
Required attributes:
- uuid
- parentsystemstructure (uuid)
- parentSystemStructure
- description
- comment
Optional attributes:
- parentdevicestructure (uuid)
- parentDeviceStructure
- index
"""
)
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = """
OK. Response is true if all name element commands validated ok, false otherwise.
Responses contain array with result for each name element command. Message and details are available if no response is available.
""",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponseBooleanList.class))),
description = "OK. Response is true if all name elements validated ok, false otherwise. Responses contain array with result for each name element.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBooleanList.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/validateupdate",
value = "/validateUpdate",
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<ResponseBooleanList> validateNamesUpdate(
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of name element commands",
required = true,
description = "array of name elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = NameElementCommand.class,
requiredProperties = {"uuid","parentsystemstructure","description","comment"}))))
@RequestBody List<NameElementCommand> nameElements);
implementation = NameElementCommandUpdate.class,
requiredProperties = {"uuid","parentSystemStructure","description"}))),
required = true)
@RequestBody List<NameElementCommandUpdate> nameElementCommands);
/**
* Return if names are valid to delete by list of name element commands.
* Return if names are valid to delete by list of name elements.
* If names are valid to delete, successful delete of names can be expected.
*
* <p>
* Response is true if all name element commands validated ok, false otherwise, responses contain array
* with result for each name element command. Message and details are available if no response is available.
* Response is true if all name elements validated ok, false otherwise, responses contain array
* with result for each name element. Message and details are available if no response is available.
* </p>
*
* @param nameElements list of name element commands
* @param nameElementCommands list of name elements
* @return if list of name elements is valid to delete
*/
@Hidden
@Operation(
summary = "Return if names are valid to delete by list of name element commands",
summary = "Return if names are valid to delete by list of name elements for confirm",
description = """
Return if names are valid to delete by list of name element commands.
Return if names are valid to delete by list of name elements.
If names are valid to delete, successful delete of names can be expected.
Required attributes:
- uuid
- comment
Other attributes are not considered.
"""
)
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = """
OK. Response is true if all name element commands validated ok, false otherwise.
Responses contain array with result for each name element command. Message and details are available if no response is available.
""",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponseBooleanList.class))),
description = "OK. Response is true if all name elements validated ok, false otherwise. Responses contain array with result for each name element.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBooleanList.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/validatedelete",
value = "/validateDelete",
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<ResponseBooleanList> validateNamesDelete(
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of name element commands",
required = true,
description = "array of name elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = NameElementCommand.class,
requiredProperties = {"uuid","comment"}))))
@RequestBody List<NameElementCommand> nameElements);
implementation = NameElementCommandConfirm.class,
requiredProperties = {"uuid"}))),
required = true)
@RequestBody List<NameElementCommandConfirm> nameElementCommands);
// ----------------------------------------------------------------------------------------------------
/**
* Update names by list of name element commands.
* Update names by list of name elements.
* Return list of name elements for updated names.
*
* @param nameElements list of name element commands
* @param nameElementCommands list of name elements
* @return list of name elements for updated names
*/
@Operation(
summary = "Update names by array of name element commands",
summary = "Update names by array of name elements",
description = """
Update names by array of name element commands.
Update names by array of name elements.
Return array of name elements for updated names.
Required attributes:
- uuid
- parentsystemstructure (uuid)
- parentSystemStructure
- description
- comment
Optional attributes:
- parentdevicestructure (uuid)
- parentDeviceStructure
- index
"""
)
""",
security = {@SecurityRequirement(name = "bearerAuth")})
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
......@@ -1082,220 +692,113 @@ public interface INames {
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "401",
description = "Unauthorized. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "403",
description = "Forbidden. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "404",
description = "Not Found. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@PutMapping(
produces = {"application/json"},
consumes = {"application/json"})
@PreAuthorize(SecurityConfiguration.IS_ADMINISTRATOR_OR_USER)
public List<NameElement> updateNames(
@AuthenticationPrincipal UserDetails user,
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of name element commands",
required = true,
description = "array of name elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = NameElementCommand.class,
requiredProperties = {"uuid","parentsystemstructure","description","comment"}))))
@RequestBody List<NameElementCommand> nameElements);
implementation = NameElementCommandUpdate.class,
requiredProperties = {"uuid","parentSystemStructure","description"}))),
required = true)
@RequestBody List<NameElementCommandUpdate> nameElementCommands);
// ----------------------------------------------------------------------------------------------------
/**
* Update names by upload Excel file.
* Return Excel file with name elements for updated names.
* Delete names by list of name elements.
* Return response code.
*
* @param file file
* @return Excel file
* @param nameElementCommands list of name elements
* @return response code
*/
@Operation(
summary = "Update names by upload Excel file",
summary = "Delete names by array of name elements",
description = """
Update names by upload Excel file.
Return Excel file with name elements for updated names.
Expected columns as in Excel template for names.
Delete names by array of name elements.
Required attributes:
- uuid
- parentsystemstructure (uuid)
- description
- comment
Optional attributes:
- parentdevicestructure (uuid)
- index
"""
)
""",
security = {@SecurityRequirement(name = "bearerAuth")})
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return Excel file with name elements for updated names.",
content = @Content(mediaType = ExcelUtil.MIME_TYPE_EXCEL)),
responseCode = "204",
description = "No content. Names were deleted."),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
responseCode = "401",
description = "Unauthorized. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@PutMapping(
value = "/upload",
produces = {"application/vnd.ms-excel"},
consumes = {"multipart/form-data"})
public ResponseEntity<Resource> updateNames(
@Parameter(
in = ParameterIn.DEFAULT,
description = "Excel file with name element commands",
required = true,
content = @Content(mediaType = ExcelUtil.MIME_TYPE_OPENXML_SPREADSHEET))
@RequestParam("file") MultipartFile file);
// ----------------------------------------------------------------------------------------------------
/**
* Delete names by list of name element commands.
* Return list of name elements for deleted names.
*
* @param nameElements list of name element commands
* @return list of name elements for deleted names
*/
@Operation(
summary = "Delete names by array of name element commands",
description = """
Delete names by array of name element commands.
Return array of name elements for deleted names.
Required attributes:
- uuid
- comment
Other attributes are not considered.
"""
)
@ApiResponses(value = {
responseCode = "403",
description = "Forbidden. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "200",
description = "OK. Return array of name elements for deleted names.",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = NameElement.class)))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
responseCode = "404",
description = "Not Found. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@DeleteMapping(
produces = {"application/json"},
consumes = {"application/json"})
public List<NameElement> deleteNames(
@PreAuthorize(SecurityConfiguration.IS_ADMINISTRATOR_OR_USER)
public ResponseEntity<Response> deleteNames(
@AuthenticationPrincipal UserDetails user,
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of name element commands",
required = true,
description = "array of name elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = NameElementCommand.class,
requiredProperties = {"uuid","comment"}))))
@RequestBody List<NameElementCommand> nameElements);
/**
* Delete names by upload Excel file.
* Return Excel file with name elements for deleted names.
*
* @param file file
* @return Excel file
*/
@Operation(
summary = "Delete names by upload Excel file",
description = """
Delete names by upload Excel file.
Return Excel file with name elements for deleted names.
Expected columns as in Excel template for names.
Required attributes:
- uuid
- comment
Other attributes are not considered.
"""
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return Excel file with name elements for deleted names.",
content = @Content(mediaType = ExcelUtil.MIME_TYPE_EXCEL)),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@DeleteMapping(
value = "/upload",
produces = {"application/vnd.ms-excel"},
consumes = {"multipart/form-data"})
public ResponseEntity<Resource> deleteNames(
@Parameter(
in = ParameterIn.DEFAULT,
description = "Excel file with name element commands",
required = true,
content = @Content(mediaType = ExcelUtil.MIME_TYPE_OPENXML_SPREADSHEET))
@RequestParam("file") MultipartFile file);
implementation = NameElementCommandConfirm.class,
requiredProperties = {"uuid"}))),
required = true)
@RequestBody List<NameElementCommandConfirm> nameElementCommands);
}
/*
* Copyright (C) 2024 European Spallation Source ERIC.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.openepics.names.rest.api.v1;
import org.openepics.names.rest.beans.response.Response;
import org.openepics.names.rest.beans.response.ResponseBoolean;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
/**
* This part of REST API provides validation of process variable names data for Naming application.
*
* @author Lars Johansson
*/
@Tag(name = "3. Process variable names",
description = "handle validation of process variable names data for Naming application")
@RequestMapping("/api/v1/pvNames")
public interface IPvNames {
/**
*
* @param pvname
* @return
*/
@Operation(
summary = "Return if process variable name is valid",
description = """
Return if process variable name is valid.
Expected valid if convention name is registered in Naming and property has valid format.
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Response is true if process variable name is valid, false otherwise.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBoolean.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/{pvName}/validity",
produces = {"application/json"})
public ResponseEntity<ResponseBoolean> isValidProcessVariableName(
@Parameter(
in = ParameterIn.DEFAULT,
description = "process variable name",
content = @Content(mediaType = "text/plain"))
@PathVariable("pvName") String pvName);
}
......@@ -20,28 +20,29 @@ package org.openepics.names.rest.api.v1;
import java.util.List;
import org.openepics.names.configuration.SecurityConfiguration;
import org.openepics.names.rest.beans.FieldStructure;
import org.openepics.names.rest.beans.Status;
import org.openepics.names.rest.beans.Type;
import org.openepics.names.rest.beans.element.StructureElement;
import org.openepics.names.rest.beans.element.StructureElementCommand;
import org.openepics.names.rest.beans.element.StructureElementCommandConfirm;
import org.openepics.names.rest.beans.element.StructureElementCommandCreate;
import org.openepics.names.rest.beans.element.StructureElementCommandUpdate;
import org.openepics.names.rest.beans.response.Response;
import org.openepics.names.rest.beans.response.ResponseBoolean;
import org.openepics.names.rest.beans.response.ResponseBooleanList;
import org.openepics.names.rest.beans.response.ResponsePageStructureElements;
import org.openepics.names.util.ExcelUtil;
import org.springframework.core.io.Resource;
import org.openepics.names.service.security.dto.UserDetails;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
......@@ -52,6 +53,7 @@ import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
/**
......@@ -59,108 +61,98 @@ import io.swagger.v3.oas.annotations.tags.Tag;
*
* @author Lars Johansson
*/
@Tag(name = "Structures",
@Tag(name = "2. Structures",
description = "handle structures data for Naming application")
@RequestMapping("/api/v1/structures")
public interface IStructures {
/*
Type - SYSTEMGROUP, SYSTEM, SUBSYSTEM, DISCIPLINE, DEVICEGROUP, DEVICETYPE
Status - APPROVED, ARCHIVED, CANCELLED, PENDING, REJECTED
FieldStructure - UUID, PARENT, NAME, MNEMONIC, MNEMONICEQUIVALENCE, MNEMONICPATH, DESCRIPTION
StructureElementCommandCreate - type, parent, mnemonic, ordering, description
StructureElementCommandUpdate - uuid, type, parent, mnemonic, ordering, description
StructureElementCommandConfirm - uuid, type
----------------------------------------------------------------------------------------------------
converted into StructureElementCommand
----------------------------------------------------------------------------------------------------
StructureElementCommand - subset of StructureElement attributes
StructureElement
uuid (UUID)
type (Type)
parent (UUID)
name (String)
mnemonic (String)
ordering (String)
description (String)
comment (String)
-------------------------
mnemonicpath (String)
mnemonicPath (String)
level (Integer)
status (Status)
latest (Boolean)
deleted (Boolean)
when (Date)
who (String)
authentication/authorization
3 levels - no, user, administrator
no - read
user - create, update, delete
administrator - approve, reject (, checkdevices)
mnemonic path for structure includes all levels of mnemonics
comment (String)
Methods
create POST /structures - createStructures (List<StructureElementCommand>)
create POST /structures/upload - createStructures (MultipartFile)
----------------------------------------------------------------------------------------------------
read GET /structures/{type} - readStructures (Type, Status[], Boolean, String, String, String, String, String, String, String, FieldStructure, Boolean, Integer, Integer)
read GET /structures/{type}/download - readStructuresDownload (Type, Status[], Boolean, String, String, String, String, String, String, String, FieldStructure, Boolean, Integer, Integer)
read GET /structures/children/{uuid} - readStructuresChildren (String, Type, Status[], Boolean, String, String, String, String, String, FieldStructure, Boolean, Integer, Integer)
read GET /structures/mnemonic/{mnemonic} - readStructuresMnemonic (String, FieldStructure, Boolean, Integer, Integer, FieldStructure, Boolean, Integer, Integer)
read GET /structures/mnemonicpath/{mnemonicpath} - readStructuresMnemonicpath (String, FieldStructure, Boolean, Integer, Integer, FieldStructure, Boolean, Integer, Integer)
read GET /structures/history/{uuid} - readStructuresHistory (String, Type, FieldStructure, Boolean, Integer, Integer)
create POST /structures - createStructures
----------------------------------------------------------------------------------------------------
read GET /structures/equivalence/{mnemonic} - equivalenceMnemonic (String)
read GET /structures/exists/{type}/{mnemonicpath} - existsStructure (Type, String)
read GET /structures/isvalidtocreate/{type}/{mnemonicpath} - isValidToCreateStructure (Type, String)
read GET /structures - readStructures
read GET /structures/{uuid} - readStructure
read GET /structures/children/{uuid} - readStructuresChildren
read GET /structures/history/{uuid} - readStructuresHistory
----------------------------------------------------------------------------------------------------
read GET /structures/validatecreate - validateStructuresCreate (List<StructureElementCommand>)
read GET /structures/validateupdate - validateStructuresUpdate (List<StructureElementCommand>)
read GET /structures/validatedelete - validateStructuresDelete (List<StructureElementCommand>)
read GET /structures/validateapprove - validateStructuresApprove (List<StructureElementCommand>)
read GET /structures/validatecancel - validateStructuresCancel (List<StructureElementCommand>)
read GET /structures/validatereject - validateStructuresReject (List<StructureElementCommand>)
read GET /structures/exists/{type}/{mnemonicPath} - existsStructure hidden from Swagger UI
read GET /structures/isValidToCreate/{type}/{mnemonicPath} - isValidToCreateStructure hidden from Swagger UI
----------------------------------------------------------------------------------------------------
update PUT /structures - updateStructures (List<StructureElementCommand>)
update PUT /structures/upload - updateStructures (MultipartFile)
read GET /structures/validateCreate - validateStructuresCreate hidden from Swagger UI
read GET /structures/validateUpdate - validateStructuresUpdate hidden from Swagger UI
read GET /structures/validateDelete - validateStructuresDelete hidden from Swagger UI
----------------------------------------------------------------------------------------------------
delete DELETE /structures - deleteStructures (List<StructureElementCommand>)
delete DELETE /structures/upload - deleteStructures (MultipartFile)
update PUT /structures - updateStructures
----------------------------------------------------------------------------------------------------
update PATCH /structures/approve - approveStructures (List<StructureElementCommand>)
update PATCH /structures/approve/upload - approveStructures (MultipartFile)
update PATCH /structures/cancel - cancelStructures (List<StructureElementCommand>)
update PATCH /structures/cancel/upload - cancelStructures (MultipartFile)
update PATCH /structures/reject - rejectStructures (List<StructureElementCommand>)
update PATCH /structures/reject/upload - rejectStructures (MultipartFile)
delete DELETE /structures - deleteStructures
Note
/upload and /download endpoints handle Excel files
authentication/authorization
3 levels - no, user, administrator
no - read
( user )
administrator - create, update, delete
default for read is to have lifecycle attributes unless query for specific resource or specific use case
status, deleted
mnemonic path for structure includes all levels of mnemonics
*/
public static final String DEFAULT_PAGE = "0";
public static final String DEFAULT_PAGE_SIZE = "100";
public static final String DEFAULT_PAGE = "0";
public static final String DEFAULT_PAGE_SIZE = "100";
public static final String DEFAULT_SORT_FIELD_WHEN = "WHEN";
public static final String DEFAULT_SORT_ORDER_ASC = "true";
/**
* Create (propose) structures by list of structure element commands.
* Create (propose) structures by list of structure elements.
* Return list of structure elements for created structures (proposals).
*
* @param structureElements list of structure element commands
* @param structureElementCommands list of structure elements
* @return list of structure elements for created structures (proposals)
*/
@Operation(
summary = "Create (propose) structures by array of structure element commands",
summary = "Create (propose) structures by array of structure elements",
description = """
Create (propose) structures by array of structure element commands.
Create (propose) structures by array of structure elements.
Return array of structure elements for created structures (proposals).
Required attributes:
- type
- parent (System, Subsystem, DeviceGroup, DeviceType)(uuid)
- name
- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup)
- description
- comment
Uuid is created by Naming.
"""
)
Optional attributes:
- parent
- mnemonic
- ordering
Note
- Uuid is created by Naming
- Parent is required for System, Subsystem, DeviceGroup, DeviceType
- Mnemonic is required for System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup
""",
security = {@SecurityRequirement(name = "bearerAuth")})
@ApiResponses(value = {
@ApiResponse(
responseCode = "201",
......@@ -171,432 +163,203 @@ public interface IStructures {
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "401",
description = "Unauthorized. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "403",
description = "Forbidden. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "404",
description = "Not Found. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@PostMapping(
produces = {"application/json"},
consumes = {"application/json"})
@PreAuthorize(SecurityConfiguration.IS_ADMINISTRATOR)
public ResponseEntity<List<StructureElement>> createStructures(
@AuthenticationPrincipal UserDetails user,
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of structure element commands",
required = true,
description = "array of structure elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = StructureElementCommand.class,
requiredProperties = {"type","parent","name","mnemonic","description","comment"}))))
@RequestBody List<StructureElementCommand> structureElements);
/**
* Create (propose) structures by upload Excel file.
* Return Excel file with structure elements for created structures (proposals).
*
* @param file file
* @return Excel file
*/
@Operation(
summary = "Create (propose) structures by upload Excel file",
description = """
Create (propose) structures by upload Excel file.
Return Excel file with structure elements for created structures (proposals).
Expected columns as in Excel template for structures.
Required attributes:
- type
- parent (System, Subsystem, DeviceGroup, DeviceType)(uuid)
- name
- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup)
- description
- comment
Uuid is created by Naming.
"""
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "201",
description = "OK. Return Excel file with structure elements for created structures (proposals).",
content = @Content(mediaType = ExcelUtil.MIME_TYPE_EXCEL)),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@PostMapping(
value = "/upload",
produces = {"application/vnd.ms-excel"},
consumes = {"multipart/form-data"})
public ResponseEntity<Resource> createStructures(
@Parameter(
in = ParameterIn.DEFAULT,
description = "Excel file with structure element commands",
required = true,
content = @Content(mediaType = ExcelUtil.MIME_TYPE_OPENXML_SPREADSHEET))
@RequestParam("file") MultipartFile file);
implementation = StructureElementCommandCreate.class,
requiredProperties = {"type","description"}))),
required = true)
@RequestBody List<StructureElementCommandCreate> structureElementCommands);
// ----------------------------------------------------------------------------------------------------
/**
* Find valid structures (search).
* Return paged list of structure elements.
* Return list of structure elements.
* Use deleted (false) to query for active structures.
*
* @param type type of structure
* @param statuses statuses for structures
* @param deleted if deleted-only structures are to be included
* (false for non-deleted-only structures, true for deleted-only structures, not used for both cases)
* @param uuid uuid
* @param parentuuid parent uuid
* @param name name
* @param deleted if deleted structures are to be selected or not, omitted for both deleted and non-deleted structures
* (true for deleted structures, false for non-deleted structures, omitted for both deleted and non-deleted structures)
* @param parent parent uuid
* @param mnemonic mnemonic
* @param mnemonicequivalence mnemonic equivalence
* @param mnemonicpath mnemonic path
* @param mnemonicPath mnemonic path
* @param description description
* @param who who
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param page page starting from 0, offset
* @param pageSize page size, limit
* @return paged list of structure elements
* @return list of structure elements
*/
@Operation(
summary = "Find valid structures (search)",
description = """
Find valid structures (search).
Return paged array of structure elements.
"""
)
Return array of structure elements.
Use deleted (false) to query for active structures.
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return paged array of structure elements.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponsePageStructureElements.class))),
description = "OK. Return array of structure elements.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponsePageStructureElements.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/{type}",
produces = {"application/json"})
public ResponsePageStructureElements readStructures(
@Parameter(in = ParameterIn.PATH, description = "search by type of structure") @PathVariable("type") Type type,
@Parameter(in = ParameterIn.QUERY, description = "search by statuses") @RequestParam(required = false) Status[] statuses,
@Parameter(in = ParameterIn.QUERY, description = "if deleted structures are to be included or not, omitted for both deleted and not deleted structures") @RequestParam(required = false) Boolean deleted,
@Parameter(in = ParameterIn.QUERY, description = "search by uuid") @RequestParam(required = false) String uuid,
@Parameter(in = ParameterIn.QUERY, description = "search by parent uuid") @RequestParam(required = false) String parentuuid,
@Parameter(in = ParameterIn.QUERY, description = "search by name") @RequestParam(required = false) String name,
@Parameter(in = ParameterIn.QUERY, description = "search by type of structure") @RequestParam(required = false) Type type,
@Parameter(in = ParameterIn.QUERY, description = "if deleted structures are to be selected or not, omitted for both deleted and non-deleted structures") @RequestParam(required = false) Boolean deleted,
@Parameter(in = ParameterIn.QUERY, description = "search by parent uuid") @RequestParam(required = false) String parent,
@Parameter(in = ParameterIn.QUERY, description = "search by mnemonic") @RequestParam(required = false) String mnemonic,
@Parameter(in = ParameterIn.QUERY, description = "search by mnemonic equivalence") @RequestParam(required = false) String mnemonicequivalence,
@Parameter(in = ParameterIn.QUERY, description = "search by mnemonic path") @RequestParam(required = false) String mnemonicpath,
@Parameter(in = ParameterIn.QUERY, description = "search by mnemonic path") @RequestParam(required = false) String mnemonicPath,
@Parameter(in = ParameterIn.QUERY, description = "search by description") @RequestParam(required = false) String description,
@Parameter(in = ParameterIn.QUERY, description = "search by who") @RequestParam(required = false) String who,
@Parameter(in = ParameterIn.QUERY, description = "order by field") @RequestParam(required = false) FieldStructure orderBy,
@Parameter(in = ParameterIn.QUERY, description = "sort order, ascending or descending") @RequestParam(required = false) Boolean isAsc,
@Parameter(in = ParameterIn.QUERY, description = "page starting from 0, offset") @RequestParam(required = false, defaultValue = DEFAULT_PAGE) Integer page,
@Parameter(in = ParameterIn.QUERY, description = "page size, limit") @RequestParam(required = false, defaultValue = DEFAULT_PAGE_SIZE) Integer pageSize);
/**
* Find valid structures (search).
* Return Excel file with paged list of structure elements.
* Find valid structure by uuid (exact match).
* Return list of structure elements.
*
* @param type type of structure
* @param statuses statuses for structures
* @param deleted if deleted-only structures are to be included
* (false for non-deleted-only structures, true for deleted-only structures, not used for both cases)
* @param uuid uuid
* @param parentuuid parent uuid
* @param name name
* @param mnemonic mnemonic
* @param mnemonicequivalence mnemonic equivalence
* @param mnemonicpath mnemonic path
* @param description description
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param page page starting from 0, offset
* @param pageSize page size, limit
* @return paged list of structure elements
* @return list of structure elements.
*/
@Operation(
summary = "Find valid structures (search) and download Excel file",
summary = "Find valid structure by uuid (exact match)",
description = """
Find valid structures (search).
Return Excel file with paged list of structure elements.
"""
)
Find valid structure by uuid (exact match).
Return list of structure elements.
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return Excel file with paged list of structure elements.",
content = @Content(mediaType = ExcelUtil.MIME_TYPE_EXCEL)),
description = "OK. Return list of structure elements.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponsePageStructureElements.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "404",
description = "Not found. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/{type}/download",
produces = {"application/vnd.ms-excel"})
public ResponseEntity<Resource> readStructuresDownload(
@Parameter(in = ParameterIn.PATH, description = "search by type of structure") @PathVariable("type") Type type,
@Parameter(in = ParameterIn.QUERY, description = "search by statuses") @RequestParam(required = false) Status[] statuses,
@Parameter(in = ParameterIn.QUERY, description = "if deleted structures are to be included or not, omitted for both deleted and not deleted structures") @RequestParam(required = false) Boolean deleted,
@Parameter(in = ParameterIn.QUERY, description = "search by uuid") @RequestParam(required = false) String uuid,
@Parameter(in = ParameterIn.QUERY, description = "search by parent uuid") @RequestParam(required = false) String parentuuid,
@Parameter(in = ParameterIn.QUERY, description = "search by name") @RequestParam(required = false) String name,
@Parameter(in = ParameterIn.QUERY, description = "search by mnemonic") @RequestParam(required = false) String mnemonic,
@Parameter(in = ParameterIn.QUERY, description = "search by mnemonic equivalence") @RequestParam(required = false) String mnemonicequivalence,
@Parameter(in = ParameterIn.QUERY, description = "search by mnemonic path") @RequestParam(required = false) String mnemonicpath,
@Parameter(in = ParameterIn.QUERY, description = "search by description") @RequestParam(required = false) String description,
@Parameter(in = ParameterIn.QUERY, description = "order by field") @RequestParam(required = false) FieldStructure orderBy,
@Parameter(in = ParameterIn.QUERY, description = "sort order, ascending or descending") @RequestParam(required = false) Boolean isAsc,
@Parameter(in = ParameterIn.QUERY, description = "page starting from 0, offset") @RequestParam(required = false, defaultValue = DEFAULT_PAGE) Integer page,
@Parameter(in = ParameterIn.QUERY, description = "page size, limit") @RequestParam(required = false, defaultValue = DEFAULT_PAGE_SIZE) Integer pageSize);
value = "/{uuid}",
produces = {"application/json"})
public ResponseEntity<ResponsePageStructureElements> readStructure(
@Parameter(in = ParameterIn.PATH, description = "find by uuid") @PathVariable("uuid") String uuid);
/**
* Find valid children structures by parent uuid (exact match).
* Return paged list of structure elements.
* Return list of structure elements.
* Use deleted (false) to query for active structures.
*
* @param uuid uuid
* @param type type of structure
* @param statuses statuses for structures
* @param deleted if deleted-only structures are to be included
* (false for non-deleted-only structures, true for deleted-only structures, not used for both cases)
* @param name name
* @param mnemonic mnemonic
* @param mnemonicequivalence mnemonic equivalence
* @param mnemonicpath mnemonic path
* @param description description
* @param deleted if deleted structures are to be selected or not, omitted for both deleted and non-deleted structures
* (true for deleted structures, false for non-deleted structures, omitted for both deleted and non-deleted structures)
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param page page starting from 0, offset
* @param pageSize page size, limit
* @return paged list of structure elements
* @return list of structure elements
*/
@Operation(
summary = "Find valid children structures by type and parent uuid (exact match)",
summary = "Find valid children structures by parent uuid (exact match)",
description = """
Find valid children structures by type and parent uuid (exact match).
Return paged array of structure elements.
"""
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return paged array of structure elements.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponsePageStructureElements.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/children/{uuid}",
produces = {"application/json"})
public ResponsePageStructureElements readStructuresChildren(
@Parameter(in = ParameterIn.PATH, description = "search by uuid") @PathVariable("uuid") String uuid,
@Parameter(in = ParameterIn.QUERY, description = "search by type of structure") @RequestParam(required = false) Type type,
@Parameter(in = ParameterIn.QUERY, description = "search by statuses") @RequestParam(required = false) Status[] statuses,
@Parameter(in = ParameterIn.QUERY, description = "if deleted structures are to be included or not, omitted for both deleted and not deleted structures") @RequestParam(required = false) Boolean deleted,
@Parameter(in = ParameterIn.QUERY, description = "search by name") @RequestParam(required = false) String name,
@Parameter(in = ParameterIn.QUERY, description = "search by mnemonic") @RequestParam(required = false) String mnemonic,
@Parameter(in = ParameterIn.QUERY, description = "search by mnemonic equivalence") @RequestParam(required = false) String mnemonicequivalence,
@Parameter(in = ParameterIn.QUERY, description = "search by mnemonic path") @RequestParam(required = false) String mnemonicpath,
@Parameter(in = ParameterIn.QUERY, description = "search by description") @RequestParam(required = false) String description,
@Parameter(in = ParameterIn.QUERY, description = "order by field") @RequestParam(required = false) FieldStructure orderBy,
@Parameter(in = ParameterIn.QUERY, description = "sort order, ascending or descending") @RequestParam(required = false) Boolean isAsc,
@Parameter(in = ParameterIn.QUERY, description = "page starting from 0, offset") @RequestParam(required = false, defaultValue = DEFAULT_PAGE) Integer page,
@Parameter(in = ParameterIn.QUERY, description = "page size, limit") @RequestParam(required = false, defaultValue = DEFAULT_PAGE_SIZE) Integer pageSize);
Find valid children structures by parent uuid (exact match).
Return array of structure elements.
/**
* Find valid structures by mnemonic (search).
* Return paged list of structure elements.
*
* @param mnemonic mnemonic
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param page page starting from 0, offset
* @param pageSize page size, limit
* @return paged list of structure elements
*/
@Operation(
summary = "Find valid structures by mnemonic (search)",
description = """
Find valid structures by mnemonic (search).
Return paged array of structure elements.
"""
)
Use deleted (false) to query for active structures.
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return paged array of structure elements.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponsePageStructureElements.class))),
description = "OK. Return array of structure elements.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponsePageStructureElements.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/mnemonic/{mnemonic}",
produces = {"application/json"})
public ResponsePageStructureElements readStructuresMnemonic(
@Parameter(in = ParameterIn.PATH, description = "search by mnemonic") @PathVariable("mnemonic") String mnemonic,
@Parameter(in = ParameterIn.QUERY, description = "order by field") @RequestParam(required = false) FieldStructure orderBy,
@Parameter(in = ParameterIn.QUERY, description = "sort order, ascending or descending") @RequestParam(required = false) Boolean isAsc,
@Parameter(in = ParameterIn.QUERY, description = "page starting from 0, offset") @RequestParam(required = false, defaultValue = DEFAULT_PAGE) Integer page,
@Parameter(in = ParameterIn.QUERY, description = "page size, limit") @RequestParam(required = false, defaultValue = DEFAULT_PAGE_SIZE) Integer pageSize);
/**
* Find valid structures by mnemonic path (search).
* Return paged list of structure elements.
*
* @param mnemonicpath mnemonic path
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param page page starting from 0, offset
* @param pageSize page size, limit
* @return paged list of structure elements
*/
@Operation(
summary = "Find valid structures by mnemonic path (search)",
description = """
Find valid structures by mnemonic path (search).
Return paged array of structure elements.
"""
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return paged array of structure elements.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponsePageStructureElements.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
responseCode = "404",
description = "Not found. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/mnemonicpath/{mnemonicpath}",
value = "/children/{uuid}",
produces = {"application/json"})
public ResponsePageStructureElements readStructuresMnemonicpath(
@Parameter(in = ParameterIn.PATH, description = "search by mnemonic path") @PathVariable("mnemonicpath") String mnemonicpath,
public ResponseEntity<ResponsePageStructureElements> readStructuresChildren(
@Parameter(in = ParameterIn.PATH, description = "find by uuid") @PathVariable("uuid") String uuid,
@Parameter(in = ParameterIn.QUERY, description = "if deleted structures are to be selected or not, omitted for both deleted and non-deleted structures", required = false) @RequestParam(required = false) Boolean deleted,
@Parameter(in = ParameterIn.QUERY, description = "order by field") @RequestParam(required = false) FieldStructure orderBy,
@Parameter(in = ParameterIn.QUERY, description = "sort order, ascending or descending") @RequestParam(required = false) Boolean isAsc,
@Parameter(in = ParameterIn.QUERY, description = "page starting from 0, offset") @RequestParam(required = false, defaultValue = DEFAULT_PAGE) Integer page,
......@@ -604,104 +367,54 @@ public interface IStructures {
/**
* Find history for structure by uuid (exact match).
* Return paged list of structure elements.
* Return list of structure elements.
* History consists of line of uuid.
* The line of uuid is not broken in retrieving history.
* If the uuid is found in a structure entry, the entire line of uuid is returned.
*
* @param uuid uuid
* @param type type of structure to search in
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param page page starting from 0, offset
* @param pageSize page size, limit
* @return paged list of structure elements
* @return list of structure elements
*/
@Operation(
summary = "Find history for structure by uuid (exact match)",
description = """
Find history for structure by uuid (exact match).
Return paged array of structure elements.
"""
)
Return array of structure elements.
History consists of line of uuid.
The line of uuid is not broken in retrieving history.
If the uuid is found in a structure entry, the entire line of uuid is returned.
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return paged array of structure elements.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponsePageStructureElements.class))),
description = "OK. Return array of structure elements.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponsePageStructureElements.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "404",
description = "Not found. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/history/{uuid}",
produces = {"application/json"})
public ResponsePageStructureElements readStructuresHistory(
@Parameter(in = ParameterIn.PATH, description = "search by uuid") @PathVariable("uuid") String uuid,
@Parameter(in = ParameterIn.QUERY, description = "search by type of structure") @RequestParam(required = false) Type type,
@Parameter(in = ParameterIn.QUERY, description = "order by field") @RequestParam(required = false) FieldStructure orderBy,
@Parameter(in = ParameterIn.QUERY, description = "sort order, ascending or descending") @RequestParam(required = false) Boolean isAsc,
@Parameter(in = ParameterIn.QUERY, description = "page starting from 0, offset") @RequestParam(required = false, defaultValue = DEFAULT_PAGE) Integer page,
@Parameter(in = ParameterIn.QUERY, description = "page size, limit") @RequestParam(required = false, defaultValue = DEFAULT_PAGE_SIZE) Integer pageSize);
public ResponseEntity<ResponsePageStructureElements> readStructuresHistory(
@Parameter(in = ParameterIn.PATH, description = "find by uuid") @PathVariable("uuid") String uuid);
// ----------------------------------------------------------------------------------------------------
/**
* Return mnemonic equivalence for mnemonic.
*
* @param mnemonic mnemonic to get mnemonic equivalence for
* @return mnemonic equivalence
*/
@Operation(
summary = "Return mnemonic equivalence for mnemonic",
description = "Return mnemonic equivalence for mnemonic."
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return mnemonic equivalence.",
content = @Content(
mediaType = "text/plain",
schema = @Schema(implementation = String.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/equivalence/{mnemonic}")
public String equivalenceMnemonic(
@Parameter(in = ParameterIn.PATH, description = "mnemonic to get mnemonic equivalence for") @PathVariable("mnemonic") String mnemonic);
/**
* Return if mnemonic path exists in structure (exact match).
*
......@@ -714,51 +427,46 @@ public interface IStructures {
* </ul>
* </p>
*
* <p>
* Note that method will always return false for DeviceGroup. Because DeviceGroup does not have mnemonic,
* its mnemonic path is the mnemonic of its parent (Discipline). However a query for mnemonic path
* for DeviceGroup is ambiguous as it lacks mnemonic. Purpose of method is to check is a particular entry
* exists in hierarchy of structures. Purpose of method is not to check if multiple entries match mnemonic path.
* Therefor method returns false for DeviceGroup.
* </p>
*
* @param type type of structure to search in
* @param mnemonicpath mnemonic path to find structure for
* @param mnemonicPath mnemonic path to find structure for
* @return if mnemonic path exists in structure
*/
@Hidden
@Operation(
summary = "Return if mnemonic path exists in structure (exact match)",
description = """
Return if mnemonic path exists in structure (exact match).
Returned object has three fields (message, details, response).
"""
)
Response is true if mnemonic path exists, false otherwise.
Note that method will always return false for DeviceGroup. Because DeviceGroup does not have mnemonic,
its mnemonic path is the mnemonic of its parent (Discipline). However a query for mnemonic path
for DeviceGroup is ambiguous as it lacks mnemonic. Purpose of method is to check is a particular entry
exists in hierarchy of structures. Purpose of method is not to check if multiple entries match mnemonic path.
Therefor method returns false for DeviceGroup.
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = """
OK. Response is true if mnemonic path exists, false otherwise.
Message and details are available if no response is available.
""",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponseBoolean.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
description = "OK. Response is true if mnemonic path exists, false otherwise.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBoolean.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/exists/{type}/{mnemonicpath}")
value = "/exists/{type}/{mnemonicPath}")
public ResponseEntity<ResponseBoolean> existsStructure(
@Parameter(in = ParameterIn.PATH, description = "type of structure to search in") @PathVariable("type") Type type,
@Parameter(in = ParameterIn.PATH, description = "mnemonic path to find structure for") @PathVariable("mnemonicpath") String mnemonicpath);
@Parameter(in = ParameterIn.PATH, description = "mnemonic path to find structure for") @PathVariable("mnemonicPath") String mnemonicPath);
/**
* Return if mnemonic path is valid to create in structure (exact match).
......@@ -772,9 +480,10 @@ public interface IStructures {
* </p>
*
* @param type type of structure to search in
* @param mnemonicpath mnemonic path to find structure for
* @param mnemonicPath mnemonic path to find structure for
* @return if mnemonic path is valid to create in structure
*/
@Hidden
@Operation(
summary = "Return if mnemonic path is valid to create in structure",
description = """
......@@ -785,54 +494,28 @@ public interface IStructures {
may have empty mnemonic. Another reason is that device groups has no mnemonic and is
between discipline and device type. Thus it can not be found which discipline (uuid-wise)
that a device type belongs.
"""
)
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = """
OK. Response is true if structure is valid to create, false otherwise.
Message and details are available if no response is available.
""",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponseBoolean.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
description = "OK. Response is true if structure is valid to create, false otherwise.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBoolean.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/isvalidtocreate/{type}/{mnemonicpath}",
value = "/isValidToCreate/{type}/{mnemonicPath}",
produces = {"application/json"})
public ResponseEntity<ResponseBoolean> isValidToCreateStructure(
@Parameter(in = ParameterIn.PATH, description = "type of structure to search in") @PathVariable("type") Type type,
@Parameter(in = ParameterIn.PATH, description = "mnemonic path to find structure for") @PathVariable("mnemonicpath") String mnemonicpath);
@Parameter(in = ParameterIn.PATH, description = "mnemonic path to find structure for") @PathVariable("mnemonicPath") String mnemonicPath);
// ----------------------------------------------------------------------------------------------------
/**
* Return if structures are valid to create (propose) by list of structure element commands.
* Return if structures are valid to create (propose) by list of structure elements.
* If structures are valid to create, successful create of structures can be expected.
*
* <p>
......@@ -846,79 +529,63 @@ public interface IStructures {
* </ul>
* </p>
*
* @param structureElements list of structure element commands
* @param structureElementCommands list of structure elements
* @return if list of structures is valid to create (propose)
*/
@Hidden
@Operation(
summary = "Return if structures are valid to create (propose) by list of structure element commands",
summary = "Return if structures are valid to create (propose) by list of structure elements",
description = """
Return if structures are valid to create (propose) by list of structure element commands.
Return if structures are valid to create (propose) by list of structure elements.
If structures are valid to create, successful create of structures can be expected.
Required attributes:
- type
- parent (System, Subsystem, DeviceGroup, DeviceType)(uuid)
- name
- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup)
- description
- comment
"""
)
Optional attributes:
- parent
- mnemonic
- ordering
Note
- Uuid is created by Naming
- Parent is required for System, Subsystem, DeviceGroup, DeviceType
- Mnemonic is required for System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = """
OK. Response is true if all structure element commands validated ok, false otherwise.
Responses contain array with result for each structure element command. Message and details are available if no response is available.
""",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponseBooleanList.class))),
description = "OK. Response is true if all structure elements validated ok, false otherwise. Responses contain array with result for each structure element.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBooleanList.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/validatecreate",
value = "/validateCreate",
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<ResponseBooleanList> validateStructuresCreate(
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of structure element commands",
required = true,
description = "array of structure elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = StructureElementCommand.class,
requiredProperties = {"type","parent","name","mnemonic","description","comment"}))))
@RequestBody List<StructureElementCommand> structureElements);
implementation = StructureElementCommandCreate.class,
requiredProperties = {"type","description"}))),
required = true)
@RequestBody List<StructureElementCommandCreate> structureElementCommands);
/**
* Return if structures are valid to update (propose) by list of structure element commands.
* Return if structures are valid to update (propose) by list of structure elements.
* If structures are valid to update, successful update of structures can be expected.
*
* <p>
......@@ -932,80 +599,63 @@ public interface IStructures {
* </ul>
* </p>
*
* @param structureElements list of structure element commands
* @param structureElementCommands list of structure elements
* @return if list of structures is valid to update (propose)
*/
@Hidden
@Operation(
summary = "Return if structures are valid to update (propose) by list of structure element commands",
summary = "Return if structures are valid to update (propose) by list of structure elements",
description = """
Return if structures are valid to update (propose) by list of structure element commands.
Return if structures are valid to update (propose) by list of structure elements.
If structures are valid to update, successful update of structures can be expected.
Required attributes:
- uuid
- type
- parent (System, Subsystem, DeviceGroup, DeviceType)(uuid)
- name
- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup)
- description
- comment
"""
)
Optional attributes:
- parent
- mnemonic
- ordering
Note
- Parent is required for System, Subsystem, DeviceGroup, DeviceType
- Mnemonic is required for System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = """
OK. Response is true if all structure element commands validated ok, false otherwise.
Responses contain array with result for each structure element command. Message and details are available if no response is available.
""",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponseBooleanList.class))),
description = "OK. Response is true if all structure elements validated ok, false otherwise. Responses contain array with result for each structure element.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBooleanList.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/validateupdate",
value = "/validateUpdate",
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<ResponseBooleanList> validateStructuresUpdate(
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of structure element commands",
required = true,
description = "array of structure elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = StructureElementCommand.class,
requiredProperties = {"uuid","type","parent","name","mnemonic","description","comment"}))))
@RequestBody List<StructureElementCommand> structureElements);
implementation = StructureElementCommandUpdate.class,
requiredProperties = {"uuid","type","description"}))),
required = true)
@RequestBody List<StructureElementCommandUpdate> structureElementCommands);
/**
* Return if structures are valid to delete (propose) by list of structure element commands.
* Return if structures are valid to delete (propose) by list of structure elements.
* If structures are valid to delete, successful delete of structures can be expected.
*
* <p>
......@@ -1019,1039 +669,199 @@ public interface IStructures {
* </ul>
* </p>
*
* @param structureElements list of structure element commands
* @param structureElementCommands list of structure elements
* @return if list of structures is valid to delete (propose)
*/
@Hidden
@Operation(
summary = "Return if structures are valid to delete (propose) by list of structure element commands",
summary = "Return if structures are valid to delete (propose) by list of structure elements",
description = """
Return if structures are valid to delete (propose) by list of structure element commands.
Return if structures are valid to delete (propose) by list of structure elements.
If structures are valid to delete, successful delete of structures can be expected.
Required attributes:
- uuid
- type
- comment
"""
)
""")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = """
OK. Response is true if all structure element commands validated ok, false otherwise.
Responses contain array with result for each structure element command. Message and details are available if no response is available.
""",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponseBooleanList.class))),
description = "OK. Response is true if all structure elements validated ok, false otherwise. Responses contain array with result for each structure element.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBooleanList.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/validatedelete",
value = "/validateDelete",
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<ResponseBooleanList> validateStructuresDelete(
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of structure element commands",
required = true,
description = "array of structure elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = StructureElementCommand.class,
requiredProperties = {"uuid","type","comment"}))))
@RequestBody List<StructureElementCommand> structureElements);
implementation = StructureElementCommandConfirm.class,
requiredProperties = {"uuid","type"}))),
required = true)
@RequestBody List<StructureElementCommandConfirm> structureElementCommands);
// ----------------------------------------------------------------------------------------------------
/**
* Return if structures are valid to approve by list of structure element commands.
* If structures are valid to approve, successful approve of structures can be expected.
*
* <p>
* Returned object has five fields (message, details, field, value, list).
* <ul>
* <li>message: reason, if method fails</li>
* <li>details: details, if method fails</li>
* <li>field: field, if method fails</li>
* <li>value: boolean (true/false), overall result of method</li>
* <li>list: list of response objects (with fields reason, details, field, value), one for each input element</li>
* </ul>
* </p>
* Update (propose) structures by list of structure elements.
* Return list of structure elements for updated structures (proposals).
*
* @param structureElements list of structure element commands
* @return if list of structures is valid to approve
* @param structureElementCommands list of structure elements
* @return list of structure elements for updated structures (proposals)
*/
@Hidden
@Operation(
summary = "Return if structures are valid to approve by list of structure element commands",
summary = "Update (propose) structures by array of structure elements",
description = """
Return if structures are valid to approve by list of structure element commands.
If structures are valid to approve, successful approve of structures can be expected.
Update (propose) structures by array of structure elements.
Return array of structure elements for updated structures (proposals).
Required attributes:
- uuid
- type
- parent (System, Subsystem, DeviceGroup, DeviceType)(uuid)
- name
- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup)
- description
- comment
"""
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = """
OK. Response is true if all structure element commands validated ok, false otherwise.
Responses contain array with result for each structure element command. Message and details are available if no response is available.
""",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponseBooleanList.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/validateapprove",
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<ResponseBooleanList> validateStructuresApprove(
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of structure element commands",
required = true,
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = StructureElementCommand.class,
requiredProperties = {"uuid","type","parent","name","mnemonic","description","comment"}))))
@RequestBody List<StructureElementCommand> structureElements);
/**
* Return if structures are valid to cancel by list of structure element commands.
* If structures are valid to cancel, successful cancel of structures can be expected.
*
* <p>
* Returned object has five fields (message, details, field, value, list).
* <ul>
* <li>message: reason, if method fails</li>
* <li>details: details, if method fails</li>
* <li>field: field, if method fails</li>
* <li>value: boolean (true/false), overall result of method</li>
* <li>list: list of response objects (with fields reason, details, field, value), one for each input element</li>
* </ul>
* </p>
*
* @param structureElements list of structure element commands
* @return if list of structures is valid to cancel
*/
@Hidden
@Operation(
summary = "Return if structures are valid to cancel by list of structure element commands",
description = """
Return if structures are valid to cancel by list of structure element commands.
If structures are valid to cancel, successful cancel of structures can be expected.
Optional attributes:
- parent
- mnemonic
- ordering
Required attributes:
- uuid
- type
- parent (System, Subsystem, DeviceGroup, DeviceType)(uuid)
- name
- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup)
- description
- comment
"""
)
Note
- Parent is required for System, Subsystem, DeviceGroup, DeviceType
- Mnemonic is required for System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup
""",
security = {@SecurityRequirement(name = "bearerAuth")})
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = """
OK. Response is true if all structure element commands validated ok, false otherwise.
Responses contain array with result for each structure element command. Message and details are available if no response is available.
""",
description = "OK. Return array of structure elements for updated structures (proposals).",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponseBooleanList.class))),
array = @ArraySchema(schema = @Schema(implementation = StructureElement.class)))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/validatecancel",
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<ResponseBooleanList> validateStructuresCancel(
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of structure element commands",
required = true,
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = StructureElementCommand.class,
requiredProperties = {"uuid","type","parent","name","mnemonic","description","comment"}))))
@RequestBody List<StructureElementCommand> structureElements);
/**
* Return if structures are valid to reject by list of structure element commands.
* If structures are valid to reject, successful reject of structures can be expected.
*
* <p>
* Returned object has five fields (message, details, field, value, list).
* <ul>
* <li>message: reason, if method fails</li>
* <li>details: details, if method fails</li>
* <li>field: field, if method fails</li>
* <li>value: boolean (true/false), overall result of method</li>
* <li>list: list of response objects (with fields reason, details, field, value), one for each input element</li>
* </ul>
* </p>
*
* @param structureElements list of structure element commands
* @return if list of structures is valid to reject
*/
@Hidden
@Operation(
summary = "Return if structures are valid to reject by list of structure element commands",
description = """
Return if structures are valid to reject by list of structure element commands.
If structures are valid to reject, successful reject of structures can be expected.
Required attributes:
- uuid
- type
- parent (System, Subsystem, DeviceGroup, DeviceType)(uuid)
- name
- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup)
- description
- comment
"""
)
@ApiResponses(value = {
responseCode = "401",
description = "Unauthorized. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "200",
description = """
OK. Response is true if all structure element commands validated ok, false otherwise.
Responses contain array with result for each structure element command. Message and details are available if no response is available.
""",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponseBooleanList.class))),
responseCode = "403",
description = "Forbidden. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
responseCode = "404",
description = "Not Found. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@GetMapping(
value = "/validatereject",
@PutMapping(
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<ResponseBooleanList> validateStructuresReject(
@PreAuthorize(SecurityConfiguration.IS_ADMINISTRATOR)
public List<StructureElement> updateStructures(
@AuthenticationPrincipal UserDetails user,
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of structure element commands",
required = true,
description = "array of structure elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = StructureElementCommand.class,
requiredProperties = {"uuid","type","parent","name","mnemonic","description","comment"}))))
@RequestBody List<StructureElementCommand> structureElements);
implementation = StructureElementCommandUpdate.class,
requiredProperties = {"uuid","type","description"}))),
required = true)
@RequestBody List<StructureElementCommandUpdate> structureElementCommands);
// ----------------------------------------------------------------------------------------------------
/**
* Update (propose) structures by list of structure element commands.
* Return list of structure elements for updated structures (proposals).
* Delete (propose) structures by list of structure elements.
* Return response code.
*
* @param structureElements list of structure element commands
* @return list of structure elements for updated structures (proposals)
* @param structureElementCommands list of structure elements
* @return response code
*/
@Operation(
summary = "Update (propose) structures by array of structure element commands",
summary = "Delete (propose) structures by array of structure elements",
description = """
Update (propose) structures by array of structure element commands.
Return array of structure elements for updated structures (proposals).
Delete (propose) structures by array of structure elements.
Required attributes:
- uuid
- type
- parent (System, Subsystem, DeviceGroup, DeviceType)(uuid)
- name
- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup)
- description
- comment
"""
)
""",
security = {@SecurityRequirement(name = "bearerAuth")})
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return array of structure elements for updated structures (proposals).",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = StructureElement.class)))),
responseCode = "204",
description = "No content. Structures were deleted (proposals)."),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
responseCode = "401",
description = "Unauthorized. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "403",
description = "Forbidden. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "404",
description = "Not Found. Reason and information such as message, details, field are available.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@PutMapping(
@DeleteMapping(
produces = {"application/json"},
consumes = {"application/json"})
public List<StructureElement> updateStructures(
@PreAuthorize(SecurityConfiguration.IS_ADMINISTRATOR)
public ResponseEntity<Response> deleteStructures(
@AuthenticationPrincipal UserDetails user,
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of structure element commands",
required = true,
description = "array of structure elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = StructureElementCommand.class,
requiredProperties = {"uuid","type","parent","name","mnemonic","description","comment"}))))
@RequestBody List<StructureElementCommand> structureElements);
/**
* Update (propose) structures by upload Excel file.
* Return Excel file with structure elements for updated structures (proposals).
*
* @param file file
* @return Excel file
*/
@Operation(
summary = "Update (propose) structures by upload Excel file",
description = """
Update (propose) structures by upload Excel file.
Return Excel file with structure elements for updated structures (proposals).
Expected columns as in Excel template for structures.
Required attributes:
- uuid
- type
- parent (System, Subsystem, DeviceGroup, DeviceType)(uuid)
- name
- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup)
- description
- comment
"""
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return Excel file with structure elements for updated structures (proposals).",
content = @Content(mediaType = ExcelUtil.MIME_TYPE_EXCEL)),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@PutMapping(
value = "/upload",
produces = {"application/vnd.ms-excel"},
consumes = {"multipart/form-data"})
public ResponseEntity<Resource> updateStructures(
@Parameter(
in = ParameterIn.DEFAULT,
description = "Excel file with structure element commands",
required = true,
content = @Content(mediaType = ExcelUtil.MIME_TYPE_OPENXML_SPREADSHEET))
@RequestParam("file") MultipartFile file);
// ----------------------------------------------------------------------------------------------------
/**
* Delete (propose) structures by list of structure element commands.
* Return list of structure elements for deleted structures (proposals).
*
* @param structureElements list of structure element commands
* @return list of structure elements for deleted structures (proposals)
*/
@Operation(
summary = "Delete (propose) structures by array of structure element commands",
description = """
Delete (propose) structures by array of structure element commands.
Return array of structure elements for deleted structures (proposals).
Required attributes:
- uuid
- type
- comment
Other attributes are not considered.
"""
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return array of structure elements for deleted structures (proposals).",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = StructureElement.class)))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@DeleteMapping(
produces = {"application/json"},
consumes = {"application/json"})
public List<StructureElement> deleteStructures(
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of structure element commands",
required = true,
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = StructureElementCommand.class,
requiredProperties = {"uuid","type","comment"}))))
@RequestBody List<StructureElementCommand> structureElements);
/**
* Delete (propose) structures by upload Excel file.
* Return Excel file with structure elements for deleted structures (proposals).
*
* @param file file
* @return Excel file
*/
@Operation(
summary = "Delete (propose) structures by upload Excel file",
description = """
Delete (propose) structures by upload Excel file.
Return Excel file with structure elements for deleted structures (proposals).
Expected columns as in Excel template for structures.
Required attributes:
- uuid
- type
- comment
Other attributes are not considered.
"""
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return Excel file with structure elements for deleted structures (proposals).",
content = @Content(mediaType = ExcelUtil.MIME_TYPE_EXCEL)),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@DeleteMapping(
value = "/upload",
produces = {"application/vnd.ms-excel"},
consumes = {"multipart/form-data"})
public ResponseEntity<Resource> deleteStructures(
@Parameter(
in = ParameterIn.DEFAULT,
description = "Excel file with structure element commands",
required = true,
content = @Content(mediaType = ExcelUtil.MIME_TYPE_OPENXML_SPREADSHEET))
@RequestParam("file") MultipartFile file);
// ----------------------------------------------------------------------------------------------------
/**
* Approve structures (proposals) by list of structure element commands.
* Return list of structure elements for approved structures.
*
* <p>
* Name is automatically created name when creation of system structure is approved.
* </p>
*
* @param structureElements list of structure element commands
* @return list of structure elements for approved structures
*/
@Operation(
summary = "Approve structures (proposals) by array of structure element commands",
description = """
Approve structures (proposals) by array of structure element commands.
Return array of structure elements for approved structures.
Name is automatically created name when creation of system structure is approved.
Required attributes:
- uuid
- type
- parent (System, Subsystem, DeviceGroup, DeviceType)(uuid)
- name
- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup)
- description
- comment
"""
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return array of structure elements for approved structures.",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = StructureElement.class)))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@PatchMapping(
value = "/approve",
produces = {"application/json"},
consumes = {"application/json"})
public List<StructureElement> approveStructures(
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of structure element commands",
required = true,
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = StructureElementCommand.class,
requiredProperties = {"uuid","type","parent","name","mnemonic","description","comment"}))))
@RequestBody List<StructureElementCommand> structureElements);
/**
* Approve structures (proposals) by upload Excel file.
* Return Excel file with structure elements for approved structures.
*
* <p>
* Name is automatically created name when creation of system structure is approved.
* </p>
*
* @param structureElements list of structure elements
* @return Excel file
*/
@Operation(
summary = "Approve structures (proposals) by upload Excel file",
description = """
Approve structures (proposals) by upload Excel file.
Return Excel file with structure elements for for approved structures.
Name is automatically created name when creation of system structure is approved.
Expected columns as in Excel template for structures.
Required attributes:
- uuid
- type
- parent (System, Subsystem, DeviceGroup, DeviceType)(uuid)
- name
- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup)
- description
- comment
"""
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return Excel file with structure elements for approved structures.",
content = @Content(mediaType = ExcelUtil.MIME_TYPE_EXCEL)),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@PatchMapping(
value = "/approve/upload",
produces = {"application/vnd.ms-excel"},
consumes = {"multipart/form-data"})
public ResponseEntity<Resource> approveStructures(
@Parameter(
in = ParameterIn.DEFAULT,
description = "Excel file with structure element commands",
required = true,
content = @Content(mediaType = ExcelUtil.MIME_TYPE_OPENXML_SPREADSHEET))
@RequestParam("file") MultipartFile file);
/**
* Cancel structures (proposals) by list of structure element commands.
* Return list of cancelled structure elements.
*
* @param structureElements list of structure elements
* @return list of structure elements for cancelled structures
*/
@Operation(
summary = "Cancel structures (proposals) by array of structure element commands",
description = """
Cancel structures (proposals) by array of structure element commands.
Return array of structure elements for cancelled structures.
Required attributes:
- uuid
- type
- parent (System, Subsystem, DeviceGroup, DeviceType)(uuid)
- name
- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup)
- description
- comment
"""
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return array of structure elements for cancelled structures.",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = StructureElement.class)))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@PatchMapping(
value = "/cancel",
produces = {"application/json"},
consumes = {"application/json"})
public List<StructureElement> cancelStructures(
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of structure element commands",
required = true,
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = StructureElementCommand.class,
requiredProperties = {"uuid","type","parent","name","mnemonic","description","comment"}))))
@RequestBody List<StructureElementCommand> structureElements);
/**
* Cancel structures (proposals) by upload Excel file.
* Return Excel file with cancelled structure elements.
*
* @param structureElements list of structure elements
* @return Excel file
*/
@Operation(
summary = "Cancel structures (proposals) by upload Excel file",
description = """
Cancel structures (proposals) by upload Excel file.
Return Excel file with structure elements for cancelled structures.
Expected columns as in Excel template for structures.
Required attributes:
- uuid
- type
- parent (System, Subsystem, DeviceGroup, DeviceType)(uuid)
- name
- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup)
- description
- comment
"""
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return Excel file with structure elements for cancelled structures.",
content = @Content(mediaType = ExcelUtil.MIME_TYPE_EXCEL)),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@PatchMapping(
value = "/cancel/upload",
produces = {"application/vnd.ms-excel"},
consumes = {"multipart/form-data"})
public ResponseEntity<Resource> cancelStructures(
@Parameter(
in = ParameterIn.DEFAULT,
description = "Excel file with structure element commands",
required = true,
content = @Content(mediaType = ExcelUtil.MIME_TYPE_OPENXML_SPREADSHEET))
@RequestParam("file") MultipartFile file);
/**
* Reject structures (proposals) by list of structure element commands.
* Return list of rejected structure elements.
*
* @param structureElements list of structure element commands
* @return list of structure elements for rejected structures
*/
@Operation(
summary = "Reject structures (proposals) by array of structure element commands",
description = """
Reject structures (proposals) by array of structure element commands.
Return array of structure elements for rejected structures.
Required attributes:
- uuid
- type
- parent (System, Subsystem, DeviceGroup, DeviceType)(uuid)
- name
- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup)
- description
- comment
"""
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return array of structure elements for rejected structures.",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = StructureElement.class)))),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@PatchMapping(
value = "/reject",
produces = {"application/json"},
consumes = {"application/json"})
public List<StructureElement> rejectStructures(
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of structure element commands",
required = true,
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = StructureElementCommand.class,
requiredProperties = {"uuid","type","parent","name","mnemonic","description","comment"}))))
@RequestBody List<StructureElementCommand> structureElements);
/**
* Reject structures (proposals) by upload Excel file.
* Return Excel file with rejected structure elements.
*
* @param structureElements list of structure elements
* @return Excel file
*/
@Operation(
summary = "Reject structures (proposals) by upload Excel file",
description = """
Reject structures (proposals) by upload Excel file.
Return Excel file with structure elements for rejected structures.
Expected columns as in Excel template for structures.
Required attributes:
- uuid
- type
- parent (System, Subsystem, DeviceGroup, DeviceType)(uuid)
- name
- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup)
- description
- comment
"""
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "OK. Return Excel file with structure elements for rejected structures.",
content = @Content(mediaType = ExcelUtil.MIME_TYPE_EXCEL)),
@ApiResponse(
responseCode = "400",
description = "Bad request. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "409",
description = "Conflict. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error. Reason and information such as message, details, field are available.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Response.class)))
})
@PatchMapping(
value = "/reject/upload",
produces = {"application/vnd.ms-excel"},
consumes = {"multipart/form-data"})
public ResponseEntity<Resource> rejectStructures(
@Parameter(
in = ParameterIn.DEFAULT,
description = "Excel file with structure element commands",
required = true,
content = @Content(mediaType = ExcelUtil.MIME_TYPE_OPENXML_SPREADSHEET))
@RequestParam("file") MultipartFile file);
implementation = StructureElementCommandConfirm.class,
requiredProperties = {"uuid","type"}))),
required = true)
@RequestBody List<StructureElementCommandConfirm> structureElementCommands);
}
......@@ -21,7 +21,7 @@ package org.openepics.names.rest.beans;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* This enum represents fields for name in beans and for communication.
* This enum represents fields for name in beans and for communication.
*
* @author Lars Johansson
*/
......@@ -33,15 +33,13 @@ public enum FieldName {
UUID,
@Schema(description = "Name (verbose) of the name.")
NAME,
@Schema(description = "Name equivalence of the name.")
NAMEEQUIVALENCE,
@Schema(description = "Mnemonic path for for the system structure.")
SYSTEMSTRUCTURE,
@Schema(description = "Mnemonic path for for the device structure.")
DEVICESTRUCTURE,
@Schema(description = "Index of the name.")
INDEX,
@Schema(description = "Description of the name.")
@Schema(description = "Description (verbose) of the name.")
DESCRIPTION,
@Schema(description = "Date and time when the name was created.")
WHEN;
......
......@@ -21,7 +21,7 @@ package org.openepics.names.rest.beans;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* This enum represents fields for structures in beans and for communication.
* This enum represents fields for structures in beans and for communication.
*
* @author Lars Johansson
*/
......@@ -33,15 +33,13 @@ public enum FieldStructure {
UUID,
@Schema(description = "Identity for the structure entry parent (if the structure entry has a parent).")
PARENT,
@Schema(description = "Name of the structure entry.")
NAME,
@Schema(description = "Mnemonic of the structure entry.")
MNEMONIC,
@Schema(description = "Mnemonic equivalence of the structure entry.")
MNEMONICEQUIVALENCE,
@Schema(description = "Mnemonic path for for the structure entry.")
MNEMONICPATH,
@Schema(description = "Description of the structure entry.")
@Schema(description = "Ordering of the structure entry.")
ORDERING,
@Schema(description = "Description (verbose) of the structure entry.")
DESCRIPTION,
@Schema(description = "Date and time when the structure entry was created.")
WHEN;
......
......@@ -27,7 +27,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
*/
@Schema(description = "A collection of values for type of structure entry. "
+ "It is used to show what kind of entry and which level in parent / child hierarchy "
+ "for system structure and device structure.")
+ "for system structure and device structure. ")
public enum Type {
@Schema(description = "System structure 1st level.")
......
......@@ -18,8 +18,8 @@
package org.openepics.names.rest.beans.element;
import java.io.Serializable;
import java.util.Date;
import java.util.Objects;
import java.util.UUID;
import org.openepics.names.rest.beans.Status;
......@@ -27,7 +27,7 @@ import org.openepics.names.rest.beans.Status;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* Bean (data transfer object) for communication and (json, xml) serialization.
* Bean (data transfer object) for communication and (json) serialization.
* Intended for operations that read names.
*
* @author Lars Johansson
......@@ -36,29 +36,24 @@ import io.swagger.v3.oas.annotations.media.Schema;
A collection of attributes that is used to encapsulate a name.
It is used to show information for a name.
""")
public class NameElement extends NameElementCommand implements Serializable {
/**
*
*/
private static final long serialVersionUID = 2716415801117244814L;
public class NameElement extends NameElementCommand {
@Schema(description = "Mnemonic path for for the system structure.")
private String systemstructure;
private String systemStructure;
@Schema(description = "Mnemonic path for for the device structure.")
private String devicestructure;
private String deviceStructure;
@Schema(description = "Name (verbose) of the name entry.")
private String name;
@Schema(description = "Status of the name entry.")
private Status status;
@Schema(description = "If the name entry is latest (with status APPROVED) in its line of entries.")
private Boolean latest;
@Schema(description = "If the name entry is deleted.")
private Boolean deleted;
@Schema(description = "Date and time when the name entry was created.")
private Date when;
@Schema(description = "Name (user) of who created the name entry.")
private String who;
@Schema(description = "Comment of the name entry.")
private String comment;
/**
* Public constructor.
......@@ -71,64 +66,47 @@ public class NameElement extends NameElementCommand implements Serializable {
* Public constructor.
*
* @param uuid uuid
* @param parentsystemstructure parent system structure uuid
* @param parentdevicestructure parent device structure uuid
* @param index index
* @param description description
* @param comment comment
*/
public NameElement(
UUID uuid, UUID parentsystemstructure, UUID parentdevicestructure, String index,
String description, String comment) {
super(uuid, parentsystemstructure, parentdevicestructure, index, description, comment);
}
/**
* Public constructor.
*
* @param uuid uuid
* @param parentsystemstructure parent system structure uuid
* @param parentdevicestructure parent device structure uuid
* @param parentSystemStructure parent system structure uuid
* @param parentDeviceStructure parent device structure uuid
* @param index index
* @param description description
* @param comment comment
* @param systemstructure system structure mnemonic path
* @param devicestructure device structure mnemonic path
* @param systemStructure system structure mnemonic path
* @param deviceStructure device structure mnemonic path
* @param name name
* @param status status
* @param latest latest
* @param deleted deleted
* @param when when
* @param who who
* @param comment comment
*/
public NameElement(
UUID uuid, UUID parentsystemstructure, UUID parentdevicestructure, String index,
String description, String comment,
String systemstructure, String devicestructure, String name,
Status status, Boolean latest, Boolean deleted,
Date when, String who) {
super(uuid, parentsystemstructure, parentdevicestructure, index, description, comment);
this.systemstructure = systemstructure;
this.devicestructure = devicestructure;
UUID uuid, UUID parentSystemStructure, UUID parentDeviceStructure,
String index, String description,
String systemStructure, String deviceStructure, String name,
Status status, Boolean deleted,
Date when, String who, String comment) {
super(uuid, parentSystemStructure, parentDeviceStructure, index, description);
this.systemStructure = systemStructure;
this.deviceStructure = deviceStructure;
this.name = name;
this.status = status;
this.latest = latest;
this.deleted = deleted;
this.when = when;
this.who = who;
this.comment = comment;
}
public String getSystemstructure() {
return systemstructure;
public String getSystemStructure() {
return systemStructure;
}
public void setSystemstructure(String systemstructure) {
this.systemstructure = systemstructure;
public void setSystemStructure(String systemStructure) {
this.systemStructure = systemStructure;
}
public String getDevicestructure() {
return devicestructure;
public String getDeviceStructure() {
return deviceStructure;
}
public void setDevicestructure(String devicestructure) {
this.devicestructure = devicestructure;
public void setDeviceStructure(String deviceStructure) {
this.deviceStructure = deviceStructure;
}
public String getName() {
return name;
......@@ -142,12 +120,6 @@ public class NameElement extends NameElementCommand implements Serializable {
public void setStatus(Status status) {
this.status = status;
}
public Boolean isLatest() {
return latest;
}
public void setLatest(Boolean latest) {
this.latest = latest;
}
public Boolean isDeleted() {
return deleted;
}
......@@ -166,6 +138,12 @@ public class NameElement extends NameElementCommand implements Serializable {
public void setWho(String who) {
this.who = who;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
@Override
public boolean equals(Object obj) {
......@@ -187,15 +165,15 @@ public class NameElement extends NameElementCommand implements Serializable {
return false;
}
if (getSystemstructure() == null) {
if (other.getSystemstructure() != null)
if (getSystemStructure() == null) {
if (other.getSystemStructure() != null)
return false;
} else if (!getSystemstructure().equals(other.getSystemstructure()))
} else if (!getSystemStructure().equals(other.getSystemStructure()))
return false;
if (getDevicestructure() == null) {
if (other.getDevicestructure() != null)
if (getDeviceStructure() == null) {
if (other.getDeviceStructure() != null)
return false;
} else if (!getDevicestructure().equals(other.getDevicestructure()))
} else if (!getDeviceStructure().equals(other.getDeviceStructure()))
return false;
if (getName() == null) {
if (other.getName() != null)
......@@ -207,11 +185,6 @@ public class NameElement extends NameElementCommand implements Serializable {
return false;
} else if (!getStatus().equals(other.getStatus()))
return false;
if (isLatest() == null) {
if (other.isLatest() != null)
return false;
} else if (!isLatest().equals(other.isLatest()))
return false;
if (isDeleted() == null) {
if (other.isDeleted() != null)
return false;
......@@ -227,24 +200,33 @@ public class NameElement extends NameElementCommand implements Serializable {
return false;
} else if (!getWho().equals(other.getWho()))
return false;
if (getComment() == null) {
if (other.getComment() != null)
return false;
} else if (!getComment().equals(other.getComment()))
return false;
return true;
}
@Override
public int hashCode() {
return Objects.hash(getUuid(), getWhen(), getComment());
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append("\"uuid\": " + getUuid());
sb.append(", \"parentsystemstructure\": " + getParentsystemstructure());
sb.append(", \"parentdevicestructure\": " + getParentdevicestructure());
sb.append(", \"systemstructure\": " + getSystemstructure());
sb.append(", \"devicestructure\": " + getDevicestructure());
sb.append(", \"parentSystemStructure\": " + getParentSystemStructure());
sb.append(", \"parentDeviceStructure\": " + getParentDeviceStructure());
sb.append(", \"systemStructure\": " + getSystemStructure());
sb.append(", \"deviceStructure\": " + getDeviceStructure());
sb.append(", \"index\": " + getIndex());
sb.append(", \"name\": " + getName());
sb.append(", \"description\": " + getDescription());
sb.append(", \"name\": " + getName());
sb.append(", \"status\": " + getStatus());
sb.append(", \"latest\": " + isLatest());
sb.append(", \"deleted\": " + isDeleted());
sb.append(", \"when\": " + getWhen());
sb.append(", \"who\": " + getWho());
......@@ -259,7 +241,6 @@ public class NameElement extends NameElementCommand implements Serializable {
sb.append("\"uuid\": " + getUuid());
sb.append(", \"name\": " + getName());
sb.append(", \"status\": " + getStatus());
sb.append(", \"latest\": " + isLatest());
sb.append(", \"deleted\": " + isDeleted());
sb.append("}");
return sb.toString();
......
......@@ -18,13 +18,13 @@
package org.openepics.names.rest.beans.element;
import java.io.Serializable;
import java.util.Objects;
import java.util.UUID;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* Bean (data transfer object) for communication and (json, xml) serialization.
* Bean (data transfer object) for communication and (json) serialization.
* Intended for operations that modify names.
*
* @author Lars Johansson
......@@ -33,25 +33,18 @@ import io.swagger.v3.oas.annotations.media.Schema;
A collection of attributes that is used to encapsulate a command for a name from client to server.
It is used to create, update, delete and validate a name.
""")
public class NameElementCommand implements Serializable {
/**
*
*/
private static final long serialVersionUID = -3166840982436164399L;
public class NameElementCommand {
@Schema(description = "Identity (uuid) of the name entry. Value is created server-side.")
private UUID uuid;
@Schema(description = "Identity (uuid) for the system structure parent.")
private UUID parentsystemstructure;
private UUID parentSystemStructure;
@Schema(description = "Identity (uuid) for the device structure parent (if the name entry refers to device structure).")
private UUID parentdevicestructure;
private UUID parentDeviceStructure;
@Schema(description = "Index (instance) of the name entry (if the name entry refers to device structure).")
private String index;
@Schema(description = "Description of the name entry.")
@Schema(description = "Description (verbose) of the name entry.")
private String description;
@Schema(description = "Comment of the name entry command.")
private String comment;
/**
* Public constructor.
......@@ -63,22 +56,20 @@ public class NameElementCommand implements Serializable {
* Public constructor.
*
* @param uuid uuid
* @param parentsystemstructure parent system structure uuid
* @param parentdevicestructure parent device structure uuid
* @param parentSystemStructure parent system structure uuid
* @param parentDeviceStructure parent device structure uuid
* @param index index
* @param description description
* @param comment comment
*/
public NameElementCommand(
UUID uuid, UUID parentsystemstructure, UUID parentdevicestructure, String index,
String description, String comment) {
UUID uuid, UUID parentSystemStructure, UUID parentDeviceStructure,
String index, String description) {
super();
this.uuid = uuid;
this.parentsystemstructure = parentsystemstructure;
this.parentdevicestructure = parentdevicestructure;
this.parentSystemStructure = parentSystemStructure;
this.parentDeviceStructure = parentDeviceStructure;
this.index = index;
this.description = description;
this.comment = comment;
}
public UUID getUuid() {
......@@ -87,17 +78,17 @@ public class NameElementCommand implements Serializable {
public void setUuid(UUID uuid) {
this.uuid = uuid;
}
public UUID getParentsystemstructure() {
return parentsystemstructure;
public UUID getParentSystemStructure() {
return parentSystemStructure;
}
public void setParentsystemstructure(UUID parentsystemstructure) {
this.parentsystemstructure = parentsystemstructure;
public void setParentSystemStructure(UUID parentSystemStructure) {
this.parentSystemStructure = parentSystemStructure;
}
public UUID getParentdevicestructure() {
return parentdevicestructure;
public UUID getParentDeviceStructure() {
return parentDeviceStructure;
}
public void setParentdevicestructure(UUID parentdevicestructure) {
this.parentdevicestructure = parentdevicestructure;
public void setParentDeviceStructure(UUID parentDeviceStructure) {
this.parentDeviceStructure = parentDeviceStructure;
}
public String getIndex() {
return index;
......@@ -111,12 +102,6 @@ public class NameElementCommand implements Serializable {
public void setDescription(String description) {
this.description = description;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
@Override
public boolean equals(Object obj) {
......@@ -134,24 +119,20 @@ public class NameElementCommand implements Serializable {
if (other == null)
return false;
if (!super.equals(other)) {
return false;
}
if (getUuid() == null) {
if (other.getUuid() != null)
return false;
} else if (!getUuid().equals(other.getUuid()))
return false;
if (getParentsystemstructure() == null) {
if (other.getParentsystemstructure() != null)
if (getParentSystemStructure() == null) {
if (other.getParentSystemStructure() != null)
return false;
} else if (!getParentsystemstructure().equals(other.getParentsystemstructure()))
} else if (!getParentSystemStructure().equals(other.getParentSystemStructure()))
return false;
if (getParentdevicestructure() == null) {
if (other.getParentdevicestructure() != null)
if (getParentDeviceStructure() == null) {
if (other.getParentDeviceStructure() != null)
return false;
} else if (!getParentdevicestructure().equals(other.getParentdevicestructure()))
} else if (!getParentDeviceStructure().equals(other.getParentDeviceStructure()))
return false;
if (getIndex() == null) {
if (other.getIndex() != null)
......@@ -163,25 +144,26 @@ public class NameElementCommand implements Serializable {
return false;
} else if (!getDescription().equals(other.getDescription()))
return false;
if (getComment() == null) {
if (other.getComment() != null)
return false;
} else if (!getComment().equals(other.getComment()))
return false;
return true;
}
@Override
public int hashCode() {
return Objects.hash(
getUuid(), getParentSystemStructure(), getParentDeviceStructure(), getIndex(),
getDescription());
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append("\"uuid\": " + getUuid());
sb.append(", \"parentsystemstructure\": " + getParentsystemstructure());
sb.append(", \"parentdevicestructure\": " + getParentdevicestructure());
sb.append(", \"parentSystemStructure\": " + getParentSystemStructure());
sb.append(", \"parentDeviceStructure\": " + getParentDeviceStructure());
sb.append(", \"index\": " + getIndex());
sb.append(", \"description\": " + getDescription());
sb.append(", \"comment\": " + getComment());
sb.append("}");
return sb.toString();
}
......
/*
* Copyright (C) 2023 European Spallation Source ERIC.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.openepics.names.rest.beans.element;
import java.util.Objects;
import java.util.UUID;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* Bean (data transfer object) for communication and (json) serialization.
* Intended for operations that modify names.
*
* @author Lars Johansson
*/
public class NameElementCommandConfirm {
@Schema(description = "Identity (uuid) of the name entry. Value is created server-side.")
private UUID uuid;
/**
* Public constructor.
*/
public NameElementCommandConfirm() {
}
/**
* Public constructor.
*
* @param uuid uuid
*/
public NameElementCommandConfirm(
UUID uuid) {
super();
this.uuid = uuid;
}
public UUID getUuid() {
return uuid;
}
public void setUuid(UUID uuid) {
this.uuid = uuid;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
return equals ((NameElementCommandConfirm) obj);
}
public boolean equals(NameElementCommandConfirm other) {
if (other == null)
return false;
if (getUuid() == null) {
if (other.getUuid() != null)
return false;
} else if (!getUuid().equals(other.getUuid()))
return false;
return true;
}
@Override
public int hashCode() {
return Objects.hash(getUuid());
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append("\"uuid\": " + getUuid());
sb.append("}");
return sb.toString();
}
}