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 4947 additions and 1210 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.WipSubsystem;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
/**
* Find subsystem structure (name part)information in JPA.
*
* @author Lars Johansson
*/
@Repository
public interface IWipSubsystemRepository extends JpaRepository<WipSubsystem, Long> {
// old + verification
@Query("FROM WipSubsystem sub WHERE sub.uuid = ?1")
List<WipSubsystem> findByUuid(String uuid);
@Query("FROM WipSubsystem sub WHERE sub.latest = true AND sub.mnemonic = ?1")
List<WipSubsystem> findLatestByMnemonic(String mnemonic);
// ----------------------------------------------------------------------------------------------------
@Query("FROM WipSubsystem sub WHERE sub.latest = true AND sub.uuid = ?1")
WipSubsystem findLatestByUuid(String uuid);
@Query("FROM WipSubsystem sub WHERE sub.latest = true AND sub.deleted = false AND sub.uuid = ?1")
WipSubsystem findLatestNotDeletedByUuid(String uuid);
@Query("FROM WipSubsystem sub WHERE sub.latest = true")
List<WipSubsystem> findLatest();
@Query("FROM WipSubsystem sub WHERE sub.latest = true AND sub.deleted = false")
List<WipSubsystem> findLatestNotDeleted();
@Query("FROM WipSubsystem sub WHERE sub.latest = true AND sub.deleted = false AND sub.parentUuid = ?1")
List<WipSubsystem> findLatestNotDeletedByParent(String uuid);
@Query("FROM WipSubsystem sub WHERE sub.uuid = ?1 AND sub.id < ?2 ORDER BY sub.id DESC")
List<WipSubsystem> 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.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,19 +20,30 @@ 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.NameElement;
import org.openepics.names.util.response.Response;
import org.openepics.names.util.response.ResponseBoolean;
import org.openepics.names.util.response.ResponseBooleanList;
import org.openepics.names.rest.beans.element.NameElement;
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.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;
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.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
......@@ -41,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;
/**
......@@ -48,366 +60,424 @@ 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
NameElement - uuid (UUID)
systemgroup (UUID)
system (UUID)
subsystem (UUID)
devicetype (UUID)
systemstructure (String)(mnemonic path)
devicestructure (String)(mnemonic path)
index (String)
name (String)
description (String)
status (Status)
latest (Boolean)
deleted (Boolean)
when (Date)
who (String)
comment (String)
authentication/authorization
3 levels - no, user, administrator
no - read
user - create, update, delete
( administrator )
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)
index (String)
description (String)
----------------------------------
systemStructure (String)
deviceStructure (String)
name (String)
status (Status)
deleted (Boolean)
when (Date)
who (String)
comment (String)
Methods
create POST /names - createNames(List<NameElement>)
create POST /names - createNames
----------------------------------------------------------------------------------------------------
read GET /names - readNames(Boolean, FieldName[], 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<NameElement>)
read GET /names/validateupdate - validateNamesUpdate(List<NameElement>)
read GET /names/validatedelete - validateNamesDelete(List<NameElement>)
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<NameElement>)
update PUT /names - updateNames
----------------------------------------------------------------------------------------------------
delete DELETE /names - deleteNames(List<NameElement>)
delete DELETE /names - deleteNames
Note
read GET /names/{name} - both name and uuid (name - exact and search, uuid exact)
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_SORT_FIELD_WHEN = "WHEN";
public static final String DEFAULT_SORT_ORDER_ASC = "true";
/**
* Create names by list of name elements.
* Return list of created name elements.
* Return list of name elements for created names.
*
* @param nameElements list of name elements
* @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 elements",
description = "Create names by array of name elements. "
+ "Return array of created name elements."
+ "\n\n"
+ "Name element attributes required: \n"
+ "- name \n"
+ "- description \n"
+ "- comment \n"
+ "- either of \n"
+ "-- subsystem \n"
+ "-- subsystem, device type, index \n"
+ "-- system \n"
+ "-- system, device type, index \n"
+ "-- system group \n"
+ "-- system group, device type, index"
)
description = """
Create names by array of name elements.
Return array of name elements for created names.
Required attributes:
- parentSystemStructure
- description
Optional attributes:
- parentDeviceStructure
- index
Note
- Uuid is created by Naming
""",
security = {@SecurityRequirement(name = "bearerAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. Return array of created name elements.", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = NameElement.class)))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "201",
description = "OK. Return array of name elements for created 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))),
@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))),
@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)))
})
@RequestMapping(
method = RequestMethod.POST,
@PostMapping(
produces = {"application/json"},
consumes = {"application/json"})
public List<NameElement> createNames(
@Parameter(in = ParameterIn.DEFAULT, description = "array of name elements", required = true) @RequestBody(required = true) List<NameElement> nameElements);
@PreAuthorize(SecurityConfiguration.IS_ADMINISTRATOR_OR_USER)
public ResponseEntity<List<NameElement>> createNames(
@AuthenticationPrincipal UserDetails user,
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of name elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = NameElementCommandCreate.class,
requiredProperties = {"parentSystemStructure","description"}))),
required = true)
@RequestBody List<NameElementCommandCreate> nameElementCommands);
// ----------------------------------------------------------------------------------------------------
/**
* Find valid names (search).
* 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 queryFields search fields
* @param queryValues search values corresponding to search fields
* @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 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 offset offset, page starting from 0
* @param limit limit, page size
* @param page page starting from 0, offset
* @param pageSize page size, limit
* @return list of name elements
*/
@Operation(
summary = "Find valid names (search)",
description = "Find valid names (search). "
+ "Return array of name elements."
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. Return array of name elements.", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = NameElement.class)))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@RequestMapping(
method = RequestMethod.GET,
produces = {"application/json"})
public List<NameElement> readNames(
@Parameter(in = ParameterIn.QUERY, description = "if deleted-only names are to be included, false for non-deleted-only names, true for deleted-only names, not used for both cases") @RequestParam(required = false) Boolean deleted,
@Parameter(in = ParameterIn.QUERY, description = "search fields") @RequestParam(required = false) FieldName[] queryFields,
@Parameter(in = ParameterIn.QUERY, description = "search values corresponding to search fields") @RequestParam(required = false) String[] queryValues,
@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 = "offset, page starting from 0") @RequestParam(required = false) Integer offset,
@Parameter(in = ParameterIn.QUERY, description = "limit, page size") @RequestParam(required = false) Integer limit);
description = """
Find valid names (search).
Return array of name elements.
/**
* Find valid names by name or uuid (search).
* Return list of name elements.
*
* @param name name or uuid to search for
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param offset offset, page starting from 0
* @param limit limit, page size
* @return list of name elements
*/
@Operation(
summary = "Find valid names by name or uuid (search)",
description = "Find valid names by name or uuid (search). "
+ "Return array of name elements."
)
Use deleted (false) to query for active names.
""")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. Return array of name elements.", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = NameElement.class)))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
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))),
@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)))
})
@RequestMapping(
value = "/{name}",
method = RequestMethod.GET,
@GetMapping(
produces = {"application/json"})
public List<NameElement> readNames(
@Parameter(in = ParameterIn.PATH, description = "name or uuid to search for") @PathVariable("name") String name,
public ResponsePageNameElements readNames(
@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 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 = "offset, page starting from 0") @RequestParam(required = false) Integer offset,
@Parameter(in = ParameterIn.QUERY, description = "limit, page size") @RequestParam(required = false) Integer limit);
@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 system structure mnemonic path (search).
* Find valid name by uuid (exact match).
* Return list of name elements.
*
* @param mnemonicpath mnemonic path to search for
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param offset offset, page starting from 0
* @param limit limit, page size
* @param uuid uuid
* @return list of name elements
*/
@Operation(
summary = "Find valid names by system structure mnemonic path (search)",
description = "Find valid names by system structure mnemonic path (search). "
+ "Return array of name elements."
)
summary = "Find valid name by uuid (exact match)",
description = """
Find valid name by uuid (exact match).
Return array of name elements.
""")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. Return array of name elements.", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = NameElement.class)))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
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 = "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)))
})
@RequestMapping(
value = "/systemstructure/{mnemonicpath}",
method = RequestMethod.GET,
@GetMapping(
value = "/{uuid}",
produces = {"application/json"})
public List<NameElement> readNamesSystemStructure(
@Parameter(in = ParameterIn.PATH, description = "mnemonic path to search for") @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 = "offset, page starting from 0") @RequestParam(required = false) Integer offset,
@Parameter(in = ParameterIn.QUERY, description = "limit, page size") @RequestParam(required = false) Integer limit);
public ResponseEntity<ResponsePageNameElements> readName(
@Parameter(in = ParameterIn.PATH, description = "find by uuid or name") @PathVariable("uuid") String uuid);
/**
* Find valid names by device structure mnemonic path (search).
* 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 to search for
* @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 offset offset, page starting from 0
* @param limit limit, page size
* @param page page starting from 0, offset
* @param pageSize page size, limit
* @return 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 array of name elements."
)
summary = "Find valid names by structure uuid that is referenced (exact match)",
description = """
Find valid names by structure uuid that is referenced (exact match).
Return list of name elements.
Endpoint applies for any type of structure.
Use deleted (false) to query for active names.
""")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. Return array of name elements.", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = NameElement.class)))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
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 = "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)))
})
@RequestMapping(
value = "/devicestructure/{mnemonicpath}",
method = RequestMethod.GET,
@GetMapping(
value = "/structure/{uuid}",
produces = {"application/json"})
public List<NameElement> readNamesDeviceStructure(
@Parameter(in = ParameterIn.PATH, description = "mnemonic path to search for") @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 = "offset, page starting from 0") @RequestParam(required = false) Integer offset,
@Parameter(in = ParameterIn.QUERY, description = "limit, page size") @RequestParam(required = false) Integer limit);
@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 history for name by uuid (exact match).
* 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 to find history for
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param offset offset, page starting from 0
* @param limit limit, page size
* @param uuid uuid
* @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 array of name elements."
)
description = """
Find history for name by uuid (exact match).
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 = "Method completed OK. Return array of name elements.", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = NameElement.class)))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
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 = "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)))
})
@RequestMapping(
@GetMapping(
value = "/history/{uuid}",
method = RequestMethod.GET,
produces = {"application/json"})
public List<NameElement> readNamesHistory(
@Parameter(in = ParameterIn.PATH, description = "uuid to find history for") @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 = "offset, page starting from 0") @RequestParam(required = false) Integer offset,
@Parameter(in = ParameterIn.QUERY, description = "limit, page size") @RequestParam(required = false) Integer limit);
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 = "Method completed OK. Return name equivalence.", content = @Content(mediaType = "text/plain", schema = @Schema(implementation = String.class))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@RequestMapping(
value = "/equivalence/{name}",
method = RequestMethod.GET)
public String equivalenceName(
@Parameter(in = ParameterIn.PATH, description = "name to get name equivalence for") @PathVariable("name") String name);
/**
* Return if name exists (exact match).
*
* <p>
* Response is true if name exists, false otherwise. Message and details are available if no response is available.
* Response is true if name exists, false otherwise.
* Message and details are available if no response is available.
* </p>
*
* @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 = "Method completed 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. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
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)))
})
@RequestMapping(
@GetMapping(
value = "/exists/{name}",
method = RequestMethod.GET,
produces = {"application/json"})
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 = "Method completed 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. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@RequestMapping(
value = "/islegacy/{name}",
method = RequestMethod.GET,
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?'.
*
* <p>
* Response is true if name is valid to create, false otherwise. Message and details are available if no response is available.
* Response is true if name is valid to create, false otherwise.
* Message and details are available if no response is available.
* </p>
*
* @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?'."
)
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 = "Method completed 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. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
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)))
})
@RequestMapping(
value = "/isvalidtocreate/{name}",
method = RequestMethod.GET,
@GetMapping(
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);
......@@ -415,203 +485,320 @@ public interface INames {
// ----------------------------------------------------------------------------------------------------
/**
* Return if name elements are valid to create.
* 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 elements validated ok, false otherwise, responses contain array with result for each name element. 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 elements
* @return if list of name elements is valid to create
* @param nameElementCommands list of name elements
* @return if list of names is valid to create
*/
@Hidden
@Operation(
summary = "Return if name elements are valid to create",
description = "Return if name elements are valid to create. "
+ "If names are valid to create, successful create of names can be expected."
+ "\n\n"
+ "Name element attributes required: \n"
+ "- name \n"
+ "- description \n"
+ "- comment \n"
+ "- either of \n"
+ "-- subsystem \n"
+ "-- subsystem, device type, index \n"
+ "-- system \n"
+ "-- system, device type, index \n"
+ "-- system group \n"
+ "-- system group, device type, index"
)
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 elements.
If names are valid to create, successful create of names can be expected.
Required attributes:
- parentSystemStructure
- description
Optional attributes:
- parentDeviceStructure
- index
Note
- Uuid is created by Naming
""")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. 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.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBooleanList.class))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
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 = "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)))
})
@RequestMapping(
value = "/validatecreate",
method = RequestMethod.GET,
@GetMapping(
value = "/validateCreate",
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<ResponseBooleanList> validateNamesCreate(
@Parameter(in = ParameterIn.DEFAULT, description = "array of name elements", required = true) @RequestBody(required = true) List<NameElement> nameElements);
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of name elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = NameElementCommandCreate.class,
requiredProperties = {"parentSystemStructure","parentDeviceStructure","index","description"}))),
required = true)
@RequestBody List<NameElementCommandCreate> nameElementCommands);
/**
* Return if name elements are valid to update.
* 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 elements validated ok, false otherwise, responses contain array with result for each name element. 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 elements
* @param nameElementCommands list of name elements
* @return if list of name elements is valid to update
*/
@Hidden
@Operation(
summary = "Return if name elements are valid to update",
description = "Return if name elements are valid to update. "
+ "If names are valid to update, successful update of names can be expected."
+ "\n\n"
+ "Name element attributes required: \n"
+ "- name \n"
+ "- description \n"
+ "- comment \n"
+ "- either of \n"
+ "-- subsystem \n"
+ "-- subsystem, device type, index \n"
+ "-- system \n"
+ "-- system, device type, index \n"
+ "-- system group \n"
+ "-- system group, device type, index"
)
summary = "Return if names are valid to update by list of name elements",
description = """
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.
Required attributes:
- uuid
- parentSystemStructure
- description
Optional attributes:
- parentDeviceStructure
- index
""")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. 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.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBooleanList.class))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
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 = "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)))
})
@RequestMapping(
value = "/validateupdate",
method = RequestMethod.GET,
@GetMapping(
value = "/validateUpdate",
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<ResponseBooleanList> validateNamesUpdate(
@Parameter(in = ParameterIn.DEFAULT, description = "array of name elements", required = true) @RequestBody(required = true) List<NameElement> nameElements);
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of name elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = NameElementCommandUpdate.class,
requiredProperties = {"uuid","parentSystemStructure","description"}))),
required = true)
@RequestBody List<NameElementCommandUpdate> nameElementCommands);
/**
* Return if name elements are valid to delete.
* If names are valid to update, successful delete of names can be expected.
* 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 elements validated ok, false otherwise, responses contain array with result for each name element. 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 elements
* @param nameElementCommands list of name elements
* @return if list of name elements is valid to delete
*/
@Hidden
@Operation(
summary = "Return if name elements are valid to delete",
description = "Return if name elements are valid to delete. "
+ "If names are valid to update, successful delete of names can be expected."
+ "\n\n"
+ "Name element attributes required: \n"
+ "- name \n"
+ "- description \n"
+ "- comment \n"
+ "- either of \n"
+ "-- subsystem \n"
+ "-- subsystem, device type, index \n"
+ "-- system \n"
+ "-- system, device type, index \n"
+ "-- system group \n"
+ "-- system group, device type, index"
)
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 elements.
If names are valid to delete, successful delete of names can be expected.
Required attributes:
- uuid
""")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. 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.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseBooleanList.class))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
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 = "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)))
})
@RequestMapping(
value = "/validatedelete",
method = RequestMethod.GET,
@GetMapping(
value = "/validateDelete",
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<ResponseBooleanList> validateNamesDelete(
@Parameter(in = ParameterIn.DEFAULT, description = "array of name elements", required = true) @RequestBody(required = true) List<NameElement> nameElements);
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of name elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = NameElementCommandConfirm.class,
requiredProperties = {"uuid"}))),
required = true)
@RequestBody List<NameElementCommandConfirm> nameElementCommands);
// ----------------------------------------------------------------------------------------------------
/**
* Update names by list of name elements.
* Returns list of updated name elements.
* Return list of name elements for updated names.
*
* @param nameElements list of name elements
* @return list of updated name elements
* @param nameElementCommands list of name elements
* @return list of name elements for updated names
*/
@Operation(
summary = "Update names by list of name elements",
description = "Update names by list of name elements. "
+ "Return array of updated name elements."
+ "\n\n"
+ "Name element attributes required: \n"
+ "- name \n"
+ "- description \n"
+ "- comment \n"
+ "- either of \n"
+ "-- subsystem \n"
+ "-- subsystem, device type, index \n"
+ "-- system \n"
+ "-- system, device type, index \n"
+ "-- system group \n"
+ "-- system group, device type, index"
)
summary = "Update names by array of name elements",
description = """
Update names by array of name elements.
Return array of name elements for updated names.
Required attributes:
- uuid
- parentSystemStructure
- description
Optional attributes:
- parentDeviceStructure
- index
""",
security = {@SecurityRequirement(name = "bearerAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. Return array of updated name elements.", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = NameElement.class)))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
description = "OK. Return array of name elements for updated 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))),
@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))),
@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)))
})
@RequestMapping(
method = RequestMethod.PUT,
@PutMapping(
produces = {"application/json"},
consumes = {"application/json"})
@PutMapping
@PreAuthorize(SecurityConfiguration.IS_ADMINISTRATOR_OR_USER)
public List<NameElement> updateNames(
@Parameter(in = ParameterIn.DEFAULT, description = "array of name elements", required = true) @RequestBody(required = true) List<NameElement> nameElements);
@AuthenticationPrincipal UserDetails user,
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of name elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = NameElementCommandUpdate.class,
requiredProperties = {"uuid","parentSystemStructure","description"}))),
required = true)
@RequestBody List<NameElementCommandUpdate> nameElementCommands);
// ----------------------------------------------------------------------------------------------------
/**
* Delete names by list of name elements.
* Returns list of deleted name elements.
* Return response code.
*
* @param uuid uuid
* @return list of deleted name elements
* @param nameElementCommands list of name elements
* @return response code
*/
@Operation(
summary = "Delete names by list of name elements",
description = "Delete names by list of name elements. "
+ "Return array of deleted name elements."
+ "\n\n"
+ "Name element attributes required: \n"
+ "- name \n"
+ "- description \n"
+ "- comment \n"
+ "- either of \n"
+ "-- subsystem \n"
+ "-- subsystem, device type, index \n"
+ "-- system \n"
+ "-- system, device type, index \n"
+ "-- system group \n"
+ "-- system group, device type, index"
)
summary = "Delete names by array of name elements",
description = """
Delete names by array of name elements.
Required attributes:
- uuid
""",
security = {@SecurityRequirement(name = "bearerAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. Return array of deleted name elements.", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = NameElement.class)))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
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))),
@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 = "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)))
})
@RequestMapping(
method = RequestMethod.DELETE,
@DeleteMapping(
produces = {"application/json"},
consumes = {"application/json"})
public List<NameElement> deleteNames(
@Parameter(in = ParameterIn.DEFAULT, description = "array of name elements", required = true) @RequestBody(required = true) List<NameElement> nameElements);
@PreAuthorize(SecurityConfiguration.IS_ADMINISTRATOR_OR_USER)
public ResponseEntity<Response> deleteNames(
@AuthenticationPrincipal UserDetails user,
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of name elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
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,21 +20,31 @@ 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.StructureElement;
import org.openepics.names.rest.beans.Type;
import org.openepics.names.util.response.Response;
import org.openepics.names.util.response.ResponseBoolean;
import org.openepics.names.util.response.ResponseBooleanList;
import org.openepics.names.rest.beans.element.StructureElement;
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.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;
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.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
......@@ -43,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;
/**
......@@ -50,314 +61,362 @@ 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
StructureElement - type (Type)
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)
mnemonicpath (String)
level (Integer)
ordering (String)
description (String)
-------------------------
mnemonicPath (String)
level (Integer)
status (Status)
latest (Boolean)
deleted (Boolean)
when (Date)
who (String)
comment (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
Methods
create POST /structures - createStructures (List<StructureElement>)
----------------------------------------------------------------------------------------------------
read GET /structures/{type} - readStructures (Type, Status[], Boolean, FieldStructure[], String[], FieldStructure, Boolean, Integer, Integer)
read GET /structures/children/{type}/{uuid} - readStructuresChildren (Type, 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}/{mnemonic} - 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<StructureElement>)
read GET /structures/validateupdate - validateStructuresUpdate (List<StructureElement>)
read GET /structures/validatedelete - validateStructuresDelete (List<StructureElement>)
read GET /structures/validateapprove - validateStructuresApprove (List<StructureElement>)
read GET /structures/validatecancel - validateStructuresCancel (List<StructureElement>)
read GET /structures/validatereject - validateStructuresReject (List<StructureElement>)
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<StructureElement>)
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<StructureElement>)
update PUT /structures - updateStructures
----------------------------------------------------------------------------------------------------
update PATCH /structures/approve - approveStructures (List<StructureElement>)
update PATCH /structures/cancel - cancelStructures (List<StructureElement>)
update PATCH /structures/reject - rejectStructures (List<StructureElement>)
delete DELETE /structures - deleteStructures
Note
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_SORT_FIELD_WHEN = "WHEN";
public static final String DEFAULT_SORT_ORDER_ASC = "true";
/**
* Create (propose) structures by list of structure elements.
* Return list of created structure elements (proposals).
*
* <p>
* StructureElement attributes required:
* <ul>
* <li>type</li>
* <li>parent (System, Subsystem, DeviceGroup, DeviceType)</li>
* <li>name</li>
* <li>mnemonic (System, Subsystem, Discipline, DeviceType)(may be set for SystemGroup, not allowed for DeviceGroup)</li>
* <li>description</li>
* <li>comment</li>
* </ul>
* </p>
* Return list of structure elements for created structures (proposals).
*
* @param structureElements list of structure elements
* @param structureElementCommands list of structure elements
* @return list of structure elements for created structures (proposals)
*/
@Operation(
summary = "Create (propose) structures by list of structure elements",
description = "Create (propose) structures by list of structure elements. "
+ "Return array of created structure elements (proposals)."
+ "\n\n"
+ "Structure element attributes required: \n"
+ "- type \n"
+ "- parent (System, Subsystem, DeviceGroup, DeviceType) \n"
+ "- name \n"
+ "- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup) \n"
+ "- description \n"
+ "- comment"
)
summary = "Create (propose) structures by array of structure elements",
description = """
Create (propose) structures by array of structure elements.
Return array of structure elements for created structures (proposals).
Required attributes:
- type
- description
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 = "200", description = "Method completed OK. Return array of structure elements for created structures (proposals).", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = StructureElement.class)))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "201",
description = "OK. Return array of structure elements for created 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 = "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))),
@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)))
})
@RequestMapping(
method = RequestMethod.POST,
@PostMapping(
produces = {"application/json"},
consumes = {"application/json"})
public List<StructureElement> createStructures(
@Parameter(in = ParameterIn.DEFAULT, description = "array of structure elements", required = true) @RequestBody(required = true) List<StructureElement> structureElements);
@PreAuthorize(SecurityConfiguration.IS_ADMINISTRATOR)
public ResponseEntity<List<StructureElement>> createStructures(
@AuthenticationPrincipal UserDetails user,
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of structure elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = StructureElementCommandCreate.class,
requiredProperties = {"type","description"}))),
required = true)
@RequestBody List<StructureElementCommandCreate> structureElementCommands);
// ----------------------------------------------------------------------------------------------------
/**
* Find valid structures (search).
* Return list of structure elements.
* Use deleted (false) to query for active structures.
*
* @param type type of structure to search in
* @param statuses statuses of structures to search for
* @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 queryFields search fields
* @param queryValues search values corresponding to search fields
* @param type type of structure
* @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 mnemonicPath mnemonic path
* @param description description
* @param who who
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param offset offset, page starting from 0
* @param limit limit, page size
* @param page page starting from 0, offset
* @param pageSize page size, limit
* @return list of structure elements
*/
@Operation(
summary = "Find valid structures (search)",
description = "Find valid structures (search). "
+ "Return list of structure elements."
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. Return array of structure elements.", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = StructureElement.class)))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@RequestMapping(
value = "/{type}",
method = RequestMethod.GET,
produces = {"application/json"})
@GetMapping
public List<StructureElement> readStructures(
@Parameter(in = ParameterIn.PATH, description = "type of structure to search in") @PathVariable("type") Type type,
@Parameter(in = ParameterIn.QUERY, description = "statuses of structures to search for") @RequestParam(required = false) Status[] statuses,
@Parameter(in = ParameterIn.QUERY, description = "if deleted-only names are to be included, false for non-deleted-only names, true for deleted-only names, not used for both cases") @RequestParam(required = false) Boolean deleted,
@Parameter(in = ParameterIn.QUERY, description = "search fields") @RequestParam(required = false) FieldStructure[] queryFields,
@Parameter(in = ParameterIn.QUERY, description = "search values corresponding to search fields") @RequestParam(required = false) String[] queryValues,
@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 = "offset, page starting from 0") @RequestParam(required = false) Integer offset,
@Parameter(in = ParameterIn.QUERY, description = "limit, page size") @RequestParam(required = false) Integer limit);
description = """
Find valid structures (search).
Return array of structure elements.
/**
* Find valid children structures by type and parent uuid (exact match).
*
* @param type type of structure to search in
* @param uuid uuid to find structure for
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param offset offset, page starting from 0
* @param limit limit, page size
* @return list of structure elements
*/
@Operation(
summary = "Find valid children structures by type and parent uuid (exact match)",
description = "Find valid children structures by type and parent uuid (exact match)."
)
Use deleted (false) to query for active structures.
""")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. Return array of structure elements.", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = StructureElement.class)))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
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)))
})
@RequestMapping(
value = "/children/{type}/{uuid}",
method = RequestMethod.GET,
@GetMapping(
produces = {"application/json"})
@GetMapping
public List<StructureElement> readStructuresChildren(
@Parameter(in = ParameterIn.PATH, description = "type of structure to search in") @PathVariable("type") Type type,
@Parameter(in = ParameterIn.PATH, description = "uuid to find structure for") @PathVariable("uuid") String uuid,
public ResponsePageStructureElements readStructures(
@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 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 = "offset, page starting from 0") @RequestParam(required = false) Integer offset,
@Parameter(in = ParameterIn.QUERY, description = "limit, page size") @RequestParam(required = false) Integer limit);
@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 (search).
* Find valid structure by uuid (exact match).
* Return list of structure elements.
*
* @param mnemonic mnemonic to search for
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param offset offset, page starting from 0
* @param limit limit, page size
* @return list of structure elements
* @param uuid uuid
* @return list of structure elements.
*/
@Operation(
summary = "Find valid structures by mnemonic (search)",
description = "Find valid structures by mnemonic (search). "
+ "Return list of structure elements."
)
summary = "Find valid structure by uuid (exact match)",
description = """
Find valid structure by uuid (exact match).
Return list of structure elements.
""")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. Return array of structure elements.", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = StructureElement.class)))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
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))),
@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)))
})
@RequestMapping(
value = "/mnemonic/{mnemonic}",
method = RequestMethod.GET,
@GetMapping(
value = "/{uuid}",
produces = {"application/json"})
@GetMapping
public List<StructureElement> readStructuresMnemonic(
@Parameter(in = ParameterIn.PATH, description = "mnemonic to search for") @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 = "offset, page starting from 0") @RequestParam(required = false) Integer offset,
@Parameter(in = ParameterIn.QUERY, description = "limit, page size") @RequestParam(required = false) Integer limit);
public ResponseEntity<ResponsePageStructureElements> readStructure(
@Parameter(in = ParameterIn.PATH, description = "find by uuid") @PathVariable("uuid") String uuid);
/**
* Find valid structures by mnemonic path (search).
* Find valid children structures by parent uuid (exact match).
* Return list of structure elements.
* Use deleted (false) to query for active structures.
*
* @param mnemonicpath mnemonic path to search for
* @param uuid uuid
* @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 offset offset, page starting from 0
* @param limit limit, page size
* @param page page starting from 0, offset
* @param pageSize page size, limit
* @return list of structure elements
*/
@Operation(
summary = "Find valid structures by mnemonic path (search)",
description = "Find valid structures by mnemonic path (search). "
+ "Return list of structure elements."
)
summary = "Find valid children structures by parent uuid (exact match)",
description = """
Find valid children structures by parent uuid (exact match).
Return array of structure elements.
Use deleted (false) to query for active structures.
""")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. Return array of structure elements.", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = StructureElement.class)))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
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 = "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)))
})
@RequestMapping(
value = "/mnemonicpath/{mnemonicpath}",
method = RequestMethod.GET,
@GetMapping(
value = "/children/{uuid}",
produces = {"application/json"})
@GetMapping
public List<StructureElement> readStructuresMnemonicpath(
@Parameter(in = ParameterIn.PATH, description = "mnemonic path to search for") @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 = "offset, page starting from 0") @RequestParam(required = false) Integer offset,
@Parameter(in = ParameterIn.QUERY, description = "limit, page size") @RequestParam(required = false) Integer limit);
@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 history for structure by uuid (exact match).
* 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 to find history for
* @param type type of structure to search in
* @param orderBy order by field
* @param isAsc sort order, ascending or descending
* @param offset offset, page starting from 0
* @param limit limit, page size
* @param uuid uuid
* @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 list of structure elements."
)
description = """
Find history for structure by uuid (exact match).
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 = "Method completed OK. Return array of structure elements.", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = StructureElement.class)))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
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 = "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)))
})
@RequestMapping(
@GetMapping(
value = "/history/{uuid}",
method = RequestMethod.GET,
produces = {"application/json"})
public List<StructureElement> readStructuresHistory(
@Parameter(in = ParameterIn.PATH, description = "uuid to find structure for") @PathVariable("uuid") String uuid,
@Parameter(in = ParameterIn.QUERY, description = "type of structure to search in") @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 = "offset, page starting from 0") @RequestParam(required = false) Integer offset,
@Parameter(in = ParameterIn.QUERY, description = "limit, page size") @RequestParam(required = false) Integer limit);
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 = "Method completed OK. Return mnemonic equivalence.", content = @Content(mediaType = "text/plain", schema = @Schema(implementation = String.class))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@RequestMapping(
value = "/equivalence/{mnemonic}",
method = RequestMethod.GET)
public String equivalenceMnemonic(
@Parameter(in = ParameterIn.PATH, description = "mnemonic to get mnemonic equivalence for") @PathVariable("mnemonic") String mnemonic);
/**
* Return if mnemonic exists in structure (exact match).
* Return if mnemonic path exists in structure (exact match).
*
* <p>
* Returned object has three fields (response, message, details).
......@@ -368,26 +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 mnemonic mnemonic to find structure for
* @return if mnemonic exists in structure
* @param mnemonicPath mnemonic path to find structure for
* @return if mnemonic path exists in structure
*/
@Hidden
@Operation(
summary = "Return if mnemonic exists in structure (exact match)",
description = "Return if mnemonic exists in structure (exact match). "
+ "Returned object has three fields (message, details, response)."
)
summary = "Return if mnemonic path exists in structure (exact match)",
description = """
Return if mnemonic path exists in structure (exact match).
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 = "Method completed 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. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
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)))
})
@RequestMapping(
value = "/exists/{type}/{mnemonic}",
method = RequestMethod.GET)
@GetMapping(
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 to find structure for") @PathVariable("mnemonic") String mnemonic);
@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).
......@@ -401,435 +480,388 @@ 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 = "Return if mnemonic path is valid to create in structure. "
+ "Method answers question 'would it be ok to create given mnemonic path in structure?'."
+ "\n\n"
+ "Note that method can not fully answer question posed above. One reason is that system group "
+ "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."
)
description = """
Return if mnemonic path is valid to create in structure.
Method answers question 'would it be ok to create given mnemonic path in structure?'.
Note that method can not fully answer question posed above. One reason is that system group
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 = "Method completed 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. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
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)))
})
@RequestMapping(
value = "/isvalidtocreate/{type}/{mnemonicpath}",
method = RequestMethod.GET,
@GetMapping(
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 structure elements are valid to create (propose).
* If structure elements are valid to create, successful create of structures can be expected.
* 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>
* Returned object has four fields (message, details, response, responses).
* 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>response: boolean (true/false), overall result of method</li>
* <li>responses: list of response objects (with fields reason, details, response), one for each input element</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 elements
* @return if list of structure elements is valid to create (propose)
* @param structureElementCommands list of structure elements
* @return if list of structures is valid to create (propose)
*/
@Hidden
@Operation(
summary = "Return if structure elements are valid to create (propose)",
description = "Return if structure elements are valid to create (propose). "
+ "If structure elements are valid to create, successful create of structures can be expected."
+ "\n\n"
+ "Structure element attributes required: \n"
+ "- type \n"
+ "- parent (System, Subsystem, DeviceGroup, DeviceType) \n"
+ "- name \n"
+ "- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup) \n"
+ "- description \n"
+ "- comment"
)
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 elements.
If structures are valid to create, successful create of structures can be expected.
Required attributes:
- type
- description
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 = "Method completed OK. Response is true if all structure elements validated ok, false otherwise, responses contain array with result for each structure element. 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. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
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 = "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)))
})
@RequestMapping(
value = "/validatecreate",
method = RequestMethod.GET,
@GetMapping(
value = "/validateCreate",
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<ResponseBooleanList> validateStructuresCreate(
@Parameter(in = ParameterIn.DEFAULT, description = "array of structure elements", required = true) @RequestBody(required = true) List<StructureElement> structureElements);
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of structure elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = StructureElementCommandCreate.class,
requiredProperties = {"type","description"}))),
required = true)
@RequestBody List<StructureElementCommandCreate> structureElementCommands);
/**
* Return if structure elements are valid to update (propose).
* If structure elements are valid to update, successful update of structures can be expected.
* 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>
* Returned object has four fields (message, details, response, responses).
* 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>response: boolean (true/false), overall result of method</li>
* <li>responses: list of response objects (with fields reason, details, response), one for each input element</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 elements
* @return if list of structure elements is valid to update (propose)
* @param structureElementCommands list of structure elements
* @return if list of structures is valid to update (propose)
*/
@Hidden
@Operation(
summary = "Return if structure elements are valid to update (propose)",
description = "Return if structure elements are valid to update (propose). "
+ "If structure elements are valid to update, successful update of structures can be expected."
+ "\n\n"
+ "Structure element attributes required: \n"
+ "- type \n"
+ "- parent (System, Subsystem, DeviceGroup, DeviceType) \n"
+ "- name \n"
+ "- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup) \n"
+ "- description \n"
+ "- comment"
)
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 elements.
If structures are valid to update, successful update of structures can be expected.
Required attributes:
- uuid
- type
- description
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 = "Method completed OK. Response is true if all structure elements validated ok, false otherwise, responses contain array with result for each structure element. 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. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
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 = "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)))
})
@RequestMapping(
value = "/validateupdate",
method = RequestMethod.GET,
@GetMapping(
value = "/validateUpdate",
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<ResponseBooleanList> validateStructuresUpdate(
@Parameter(in = ParameterIn.DEFAULT, description = "array of structure elements", required = true) @RequestBody(required = true) List<StructureElement> structureElements);
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of structure elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = StructureElementCommandUpdate.class,
requiredProperties = {"uuid","type","description"}))),
required = true)
@RequestBody List<StructureElementCommandUpdate> structureElementCommands);
/**
* Return if structure elements are valid to delete (propose).
* If structure elements are valid to delete, successful delete of structures can be expected.
* 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>
* Returned object has four fields (message, details, response, responses).
* 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>response: boolean (true/false), overall result of method</li>
* <li>responses: list of response objects (with fields reason, details, response), one for each input element</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 elements
* @return if list of structure elements is valid to delete (propose)
* @param structureElementCommands list of structure elements
* @return if list of structures is valid to delete (propose)
*/
@Hidden
@Operation(
summary = "Return if structure elements are valid to delete (propose)",
description = "Return if structure elements are valid to delete (propose). "
+ "If structure elements are valid to delete, successful delete of structures can be expected."
+ "\n\n"
+ "Structure element attributes required: \n"
+ "- type \n"
+ "- parent (System, Subsystem, DeviceGroup, DeviceType) \n"
+ "- name \n"
+ "- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup) \n"
+ "- description \n"
+ "- comment"
)
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 elements.
If structures are valid to delete, successful delete of structures can be expected.
Required attributes:
- uuid
- type
""")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. Response is true if all structure elements validated ok, false otherwise, responses contain array with result for each structure element. 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. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
responseCode = "200",
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 = "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)))
})
@RequestMapping(
value = "/validatedelete",
method = RequestMethod.GET,
@GetMapping(
value = "/validateDelete",
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<ResponseBooleanList> validateStructuresDelete(
@Parameter(in = ParameterIn.DEFAULT, description = "array of structure elements", required = true) @RequestBody(required = true) List<StructureElement> structureElements);
/**
* Return if structure elements are valid to approve.
* If structure elements are valid to approve, successful approve of structures can be expected.
*
* <p>
* Returned object has four fields (message, details, response, responses).
* <ul>
* <li>message: reason, if method fails</li>
* <li>details: details, if method fails</li>
* <li>response: boolean (true/false), overall result of method</li>
* <li>responses: list of response objects (with fields reason, details, response), one for each input element</li>
* </ul>
* </p>
*
* @param structureElements list of structure elements
* @return if list of structure elements is valid to approve
*/
@Operation(
summary = "Return if structure elements are valid to approve",
description = "Return if structure elements are valid to approve. "
+ "If structure elements are valid to approve, successful approve of structures can be expected."
+ "\n\n"
+ "Structure element attributes required: \n"
+ "- type \n"
+ "- parent (System, Subsystem, DeviceGroup, DeviceType) \n"
+ "- name \n"
+ "- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup) \n"
+ "- description \n"
+ "- comment"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. Response is true if all structure elements validated ok, false otherwise, responses contain array with result for each structure element. 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. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@RequestMapping(
value = "/validateapprove",
method = RequestMethod.GET,
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<ResponseBooleanList> validateStructuresApprove(
@Parameter(in = ParameterIn.DEFAULT, description = "array of structure elements", required = true) @RequestBody(required = true) List<StructureElement> structureElements);
/**
* Return if structure elements are valid to cancel.
* If structure elements are valid to cancel, successful cancel of structures can be expected.
*
* <p>
* Returned object has four fields (message, details, response, responses).
* <ul>
* <li>message: reason, if method fails</li>
* <li>details: details, if method fails</li>
* <li>response: boolean (true/false), overall result of method</li>
* <li>responses: list of response objects (with fields reason, details, response), one for each input element</li>
* </ul>
* </p>
*
* @param structureElements list of structure elements
* @return if list of structure elements is valid to cancel
*/
@Operation(
summary = "Return if structure elements are valid to cancel",
description = "Return if structure elements are valid to cancel. "
+ "If structure elements are valid to cancel, successful cancel of structures can be expected."
+ "\n\n"
+ "Structure element attributes required: \n"
+ "- type \n"
+ "- parent (System, Subsystem, DeviceGroup, DeviceType) \n"
+ "- name \n"
+ "- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup) \n"
+ "- description \n"
+ "- comment"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. Response is true if all structure elements validated ok, false otherwise, responses contain array with result for each structure element. 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. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@RequestMapping(
value = "/validatecancel",
method = RequestMethod.GET,
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<ResponseBooleanList> validateStructuresCancel(
@Parameter(in = ParameterIn.DEFAULT, description = "array of structure elements", required = true) @RequestBody(required = true) List<StructureElement> structureElements);
/**
* Return if structure elements are valid to reject.
* If structure elements are valid to reject, successful reject of structures can be expected.
*
* <p>
* Returned object has four fields (message, details, response, responses).
* <ul>
* <li>message: reason, if method fails</li>
* <li>details: details, if method fails</li>
* <li>response: boolean (true/false), overall result of method</li>
* <li>responses: list of response objects (with fields reason, details, response), one for each input element</li>
* </ul>
* </p>
*
* @param structureElements list of structure elements
* @return if list of structure elements is valid to reject
*/
@Operation(
summary = "Return if structure elements are valid to reject",
description = "Return if structure elements are valid to reject. "
+ "If structure elements are valid to reject, successful reject of structures can be expected."
+ "\n\n"
+ "Structure element attributes required: \n"
+ "- type \n"
+ "- parent (System, Subsystem, DeviceGroup, DeviceType) \n"
+ "- name \n"
+ "- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup) \n"
+ "- description \n"
+ "- comment"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. Response is true if all structure elements validated ok, false otherwise, responses contain array with result for each structure element. 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. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@RequestMapping(
value = "/validatereject",
method = RequestMethod.GET,
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<ResponseBooleanList> validateStructuresReject(
@Parameter(in = ParameterIn.DEFAULT, description = "array of structure elements", required = true) @RequestBody(required = true) List<StructureElement> structureElements);
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of structure elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = StructureElementCommandConfirm.class,
requiredProperties = {"uuid","type"}))),
required = true)
@RequestBody List<StructureElementCommandConfirm> structureElementCommands);
// ----------------------------------------------------------------------------------------------------
/**
* Update (propose) structures by list of structure elements.
* Return list of updated structure elements (proposals).
* Return list of structure elements for updated structures (proposals).
*
* @param structureElements list of structure elements
* @param structureElementCommands list of structure elements
* @return list of structure elements for updated structures (proposals)
*/
@Operation(
summary = "Update (propose) structures by list of structure elements",
description = "Update (propose) structures by list of structure elements. "
+ "Return array of updated structure elements (proposals)."
+ "\n\n"
+ "Structure element attributes required: \n"
+ "- type \n"
+ "- parent (System, Subsystem, DeviceGroup, DeviceType) \n"
+ "- name \n"
+ "- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup) \n"
+ "- description \n"
+ "- comment"
)
summary = "Update (propose) structures by array of structure elements",
description = """
Update (propose) structures by array of structure elements.
Return array of structure elements for updated structures (proposals).
Required attributes:
- uuid
- type
- description
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
""",
security = {@SecurityRequirement(name = "bearerAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed OK. Return array of structure elements for updated structures (proposals).", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = StructureElement.class)))),
@ApiResponse(responseCode = "400", description = "Bad request. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@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)))),
@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 = "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))),
@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)))
})
@RequestMapping(
method = RequestMethod.PUT,
@PutMapping(
produces = {"application/json"},
consumes = {"application/json"})
@PreAuthorize(SecurityConfiguration.IS_ADMINISTRATOR)
public List<StructureElement> updateStructures(
@Parameter(in = ParameterIn.DEFAULT, description = "array of structure elements", required = true) @RequestBody(required = true) List<StructureElement> structureElements);
@AuthenticationPrincipal UserDetails user,
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of structure elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = StructureElementCommandUpdate.class,
requiredProperties = {"uuid","type","description"}))),
required = true)
@RequestBody List<StructureElementCommandUpdate> structureElementCommands);
// ----------------------------------------------------------------------------------------------------
/**
* Delete (propose) structures by list of structure elements.
* Return list of deleted structure elements (proposals).
*
* @param structureElements list of structure elements
* @return list of structure elements for deleted structures (proposals)
*/
@Operation(
summary = "Delete (propose) structures by list of structure elements",
description = "Delete (propose) structures by list of structure elements. "
+ "Return array of deleted structure elements (proposals)."
+ "\n\n"
+ "Structure element attributes required: \n"
+ "- type \n"
+ "- parent (System, Subsystem, DeviceGroup, DeviceType) \n"
+ "- name \n"
+ "- mnemonic (System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup) \n"
+ "- description \n"
+ "- comment"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed 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. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@RequestMapping(
method = RequestMethod.DELETE,
produces = {"application/json"},
consumes = {"application/json"})
public List<StructureElement> deleteStructures(
@Parameter(in = ParameterIn.DEFAULT, description = "array of structure elements", required = true) @RequestBody(required = true) List<StructureElement> structureElements);
// ----------------------------------------------------------------------------------------------------
/**
* Approve structures (proposals) by list of structure elements.
* Return list of approved structure elements.
*
* @param structureElements list of structure elements
* @return list of structure elements for approved structures
*/
@Operation(
summary = "Approve structures (proposals) by list of structure elements",
description = "Approve structures (proposals) by list of structure elements. "
+ "Return list of approved structure elements."
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed 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. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@RequestMapping(
value = "/approve",
method = RequestMethod.PATCH,
produces = {"application/json"},
consumes = {"application/json"})
public List<StructureElement> approveStructures(
@Parameter(in = ParameterIn.DEFAULT, description = "array of structure elements", required = true) @RequestBody(required = true) List<StructureElement> structureElements);
/**
* Cancel structures (proposals) by list of structure elements.
* 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 list of structure elements",
description = "Cancel structures (proposals) by list of structure elements. "
+ "Return list of cancelled structure elements."
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed 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. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
})
@RequestMapping(
value = "/cancel",
method = RequestMethod.PATCH,
produces = {"application/json"},
consumes = {"application/json"})
public List<StructureElement> cancelStructures(
@Parameter(in = ParameterIn.DEFAULT, description = "array of structure elements", required = true) @RequestBody(required = true) List<StructureElement> structureElements);
/**
* Reject structures (proposals) by list of structure elements.
* Return list of rejected structure elements.
* Return response code.
*
* @param structureElements list of structure elements
* @return list of structure elements for rejected structures
* @param structureElementCommands list of structure elements
* @return response code
*/
@Operation(
summary = "Reject structures (proposals) by list of structure elements",
description = "Reject structures (proposals) by list of structure elements. "
+ "Return list of rejected structure elements."
)
summary = "Delete (propose) structures by array of structure elements",
description = """
Delete (propose) structures by array of structure elements.
Required attributes:
- uuid
- type
""",
security = {@SecurityRequirement(name = "bearerAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Method completed 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. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
@ApiResponse(responseCode = "500", description = "Internal server error. Message and details are available.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class)))
@ApiResponse(
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))),
@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 = "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)))
})
@RequestMapping(
value = "/reject",
method = RequestMethod.PATCH,
@DeleteMapping(
produces = {"application/json"},
consumes = {"application/json"})
public List<StructureElement> rejectStructures(
@Parameter(in = ParameterIn.DEFAULT, description = "array of structure elements", required = true) @RequestBody(required = true) List<StructureElement> structureElements);
@PreAuthorize(SecurityConfiguration.IS_ADMINISTRATOR)
public ResponseEntity<Response> deleteStructures(
@AuthenticationPrincipal UserDetails user,
@Parameter(
in = ParameterIn.DEFAULT,
description = "array of structure elements",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(
schema = @Schema(
implementation = StructureElementCommandConfirm.class,
requiredProperties = {"uuid","type"}))),
required = true)
@RequestBody List<StructureElementCommandConfirm> structureElementCommands);
}
......@@ -18,18 +18,30 @@
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
*/
@Schema(description = "A collection of values for fields for a name that may used in client query "
+ "for information to server.")
public enum FieldName {
@Schema(description = "Identity of the name. Value is set server-side.")
UUID,
@Schema(description = "Name (verbose) of the name.")
NAME,
NAMEEQUIVALENCE,
@Schema(description = "Mnemonic path for for the system structure.")
SYSTEMSTRUCTURE,
@Schema(description = "Mnemonic path for for the device structure.")
DEVICESTRUCTURE,
DESCRIPTION;
@Schema(description = "Index of the name.")
INDEX,
@Schema(description = "Description (verbose) of the name.")
DESCRIPTION,
@Schema(description = "Date and time when the name was created.")
WHEN;
}
......@@ -18,19 +18,30 @@
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
*/
@Schema(description = "A collection of values for fields for a structure entry that may used in client query "
+ "for information to server.")
public enum FieldStructure {
@Schema(description = "Identity of the structure entry. Value is set server-side.")
UUID,
@Schema(description = "Identity for the structure entry parent (if the structure entry has a parent).")
PARENT,
NAME,
@Schema(description = "Mnemonic of the structure entry.")
MNEMONIC,
MNEMONICEQUIVALENCE,
@Schema(description = "Mnemonic path for for the structure entry.")
MNEMONICPATH,
DESCRIPTION;
@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;
}
/*
* 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.rest.beans;
import java.io.Serializable;
import java.util.Date;
import java.util.UUID;
/**
* Bean (data transfer object) for communication and (json, xml) serialization.
*
* @author Lars Johansson
*/
public class NameElement extends NameStructureElement implements Serializable {
/**
*
*/
private static final long serialVersionUID = -5998490678202969520L;
private UUID systemgroup;
private UUID system;
private UUID subsystem;
private UUID devicetype;
private String systemstructure;
private String devicestructure;
private String index;
private String name;
/**
* Public constructor.
*/
public NameElement () {
}
/**
* Public constructor.
*
* @param uuid uuid
* @param systemgroup system group
* @param system system
* @param subsystem subsystem
* @param devicetype device type
* @param systemstructure system structure mnemonic path
* @param devicestructure device structure mnemonic path
* @param index instance index
* @param name name
* @param description description
* @param status status
* @param latest latest
* @param deleted deleted
* @param when when
* @param who who
* @param comment comment
*/
public NameElement (
UUID uuid,
UUID systemgroup, UUID system, UUID subsystem, UUID devicetype,
String systemstructure, String devicestructure,
String index, String name,
String description, Status status, Boolean latest, Boolean deleted,
Date when, String who, String comment) {
super(uuid, description, status, latest, deleted, when, who, comment);
setSystemgroup(systemgroup);
setSystem(system);
setSubsystem(subsystem);
setDevicetype(devicetype);
setSystemstructure(systemstructure);
setDevicestructure(devicestructure);
setIndex(index);
setName(name);
}
public UUID getSystemgroup() {
return systemgroup;
}
public void setSystemgroup(UUID systemgroup) {
this.systemgroup = systemgroup;
}
public UUID getSystem() {
return system;
}
public void setSystem(UUID system) {
this.system = system;
}
public UUID getSubsystem() {
return subsystem;
}
public void setSubsystem(UUID subsystem) {
this.subsystem = subsystem;
}
public UUID getDevicetype() {
return devicetype;
}
public void setDevicetype(UUID devicetype) {
this.devicetype = devicetype;
}
public String getSystemstructure() {
return systemstructure;
}
public void setSystemstructure(String systemstructure) {
this.systemstructure = systemstructure;
}
public String getDevicestructure() {
return devicestructure;
}
public void setDevicestructure(String devicestructure) {
this.devicestructure = devicestructure;
}
public String getIndex() {
return index;
}
public void setIndex(String index) {
this.index = index;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// utility method
public void setNameAndIndex(String name, String index) {
this.index = index;
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
return equals ((NameElement) obj);
}
public boolean equals(NameElement other) {
if (other == null)
return false;
if (!super.equals(other)) {
return false;
}
if (getSystemgroup() == null) {
if (other.getSystemgroup() != null)
return false;
} else if (!getSystemgroup().equals(other.getSystemgroup()))
return false;
if (getSystem() == null) {
if (other.getSystem() != null)
return false;
} else if (!getSystem().equals(other.getSystem()))
return false;
if (getSubsystem() == null) {
if (other.getSubsystem() != null)
return false;
} else if (!getSubsystem().equals(other.getSubsystem()))
return false;
if (getDevicetype() == null) {
if (other.getDevicetype() != null)
return false;
} else if (!getDevicetype().equals(other.getDevicetype()))
return false;
if (getSystemstructure() == null) {
if (other.getSystemstructure() != null)
return false;
} else if (!getSystemstructure().equals(other.getSystemstructure()))
return false;
if (getDevicestructure() == null) {
if (other.getDevicestructure() != null)
return false;
} else if (!getDevicestructure().equals(other.getDevicestructure()))
return false;
if (getIndex() == null) {
if (other.getIndex() != null)
return false;
} else if (!getIndex().equals(other.getIndex()))
return false;
if (getName() == null) {
if (other.getName() != null)
return false;
} else if (!getName().equals(other.getName()))
return false;
return true;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append("\"uuid\": " + getUuid());
sb.append(", \"systemgroup\": " + getSystemgroup());
sb.append(", \"system\": " + getSystem());
sb.append(", \"subsystem\": " + getSubsystem());
sb.append(", \"devicetype\": " + getDevicetype());
sb.append(", \"systemstructure\": " + getSystemstructure());
sb.append(", \"devicestructure\": " + getDevicestructure());
sb.append(", \"index\": " + getIndex());
sb.append(", \"name\": " + getName());
sb.append(", \"description\": " + getDescription());
sb.append(", \"status\": " + getStatus());
sb.append(", \"latest\": " + isLatest());
sb.append(", \"deleted\": " + isDeleted());
sb.append(", \"when\": " + getWhen());
sb.append(", \"who\": " + getWho());
sb.append(", \"comment\": " + getComment());
sb.append("}");
return sb.toString();
}
public String toStringSimple() {
StringBuilder sb = new StringBuilder();
sb.append("{");
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,17 +18,26 @@
package org.openepics.names.rest.beans;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* This enum represents status for names and structures data in beans and for communication.
*
* @author Lars Johansson
*/
@Schema(description = "A collection of values for status of a name and structure entry. "
+ "It is used to show where in its lifecycle that a name and structure entry is located.")
public enum Status {
@Schema(description = "(Proposal for) Name or structure entry has been approved by administrator.")
APPROVED,
@Schema(description = "Name or structure entry that is no longer in use with data considered history.")
ARCHIVED,
@Schema(description = "(Proposal for) Name or structure entry has been cancelled by user.")
CANCELLED,
@Schema(description = "(Proposal for) Name or structure entry has been entered by user and is pending for administrator to approve or reject.")
PENDING,
@Schema(description = "(Proposal for) Name or structure entry has been rejected by administrator.")
REJECTED;
}
......@@ -18,18 +18,29 @@
package org.openepics.names.rest.beans;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* This enum represents types for structures data in beans and for communication.
*
* @author Lars Johansson
*/
@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. ")
public enum Type {
@Schema(description = "System structure 1st level.")
SYSTEMGROUP,
@Schema(description = "System structure 2nd level.")
SYSTEM,
@Schema(description = "System structure 3rd level.")
SUBSYSTEM,
@Schema(description = "Device structure 1st level.")
DISCIPLINE,
@Schema(description = "Device structure 2nd level.")
DEVICEGROUP,
@Schema(description = "Device structure 3rd level.")
DEVICETYPE;
}