Projekt

Allgemein

Profil

Herunterladen als
Herunterladen (15 KB) Statistiken
| Zweig: | Revision:
11f5a3a7 Christian Ehringfeld
/*
* Copyright (C) 2015 Christian Ehringfeld <c.ehringfeld@t-online.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation.
*
* 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 Lesser General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
93285804 Christian Ehringfeld
#include "entityinspector.h"
e332a521 Christian Ehringfeld
#include <QDir>
#include <QDateTime>
using namespace CuteEntityManager;
93285804 Christian Ehringfeld
f12670e9 Christian Ehringfeld
EntityInspector::EntityInspector(const MsgType msgType) {
this->initLogger(msgType);
e332a521 Christian Ehringfeld
}

EntityInspector::~EntityInspector() {
if (this->logger) {
delete this->logger;
this->logger = nullptr;
}
}

bool EntityInspector::checkRegisteredEntities() {
QStringList classes = EntityInstanceFactory::getRegisteredClasses();
74d545d4 Christian Ehringfeld
classes.sort();
e332a521 Christian Ehringfeld
QString msg = QDateTime::currentDateTime().toString(Qt::ISODate) +
2cded5d4 Christian Ehringfeld
" - Start checking entities\n";
f12670e9 Christian Ehringfeld
this->logger->logMsg(msg, MsgType::INFO);
e332a521 Christian Ehringfeld
bool ok = true;
for (int i = 0; i < classes.size(); ++i) {
bool r = this->checkEntity(classes.at(i));
if (!r) {
msg = "###############################";
msg += "\n";
msg += classes.at(i) + " is erroneous!";
msg += "\n";
msg += "###############################\n";
f12670e9 Christian Ehringfeld
this->logger->logMsg(msg, MsgType::CRITICAL);
e332a521 Christian Ehringfeld
ok = false;
} else {
43457c84 Christian Ehringfeld
msg = "Entity class " + classes.at(i) + " seems ok.\n";
f12670e9 Christian Ehringfeld
this->logger->logMsg(msg, MsgType::INFO);
e332a521 Christian Ehringfeld
}
}
msg = QDateTime::currentDateTime().toString(Qt::ISODate) +
2cded5d4 Christian Ehringfeld
" - End checking entities\n";
f12670e9 Christian Ehringfeld
this->logger->logMsg(msg, MsgType::INFO);
e332a521 Christian Ehringfeld
return ok;
}

bool EntityInspector::checkEntity(QString name) {
QString msg = "--------------------\n";
43457c84 Christian Ehringfeld
msg += "Checking " + name + " now.\n";
f12670e9 Christian Ehringfeld
this->logger->logMsg(msg, MsgType::DEBUG);
auto entity = this->instantiateEntity(name);
e332a521 Christian Ehringfeld
bool ok = true;
if (entity) {
f12670e9 Christian Ehringfeld
bool relations = this->verifyRelations(entity);
bool pk = this->checkPrimaryKey(entity);
this->verifyBlobAttributes(entity);
this->verifyTransientAttributes(entity);
e332a521 Christian Ehringfeld
ok = pk && relations;
153c0e85 Christian Ehringfeld
delete entity;
entity = nullptr;
e332a521 Christian Ehringfeld
}
return ok;
}

f12670e9 Christian Ehringfeld
Entity *EntityInspector::instantiateEntity(const QString name) {
e332a521 Christian Ehringfeld
auto entity = EntityInstanceFactory::createInstance(name);
f12670e9 Christian Ehringfeld
QString msg = "";
e332a521 Christian Ehringfeld
if (entity) {
f12670e9 Christian Ehringfeld
msg = name + " is instantiable.";
10cc871a Christian Ehringfeld
this->logger->logMsg(msg, MsgType::DEBUG);
e332a521 Christian Ehringfeld
} else {
f12670e9 Christian Ehringfeld
msg = name + " is NOT instantiable!";
this->logger->logMsg(msg, MsgType::CRITICAL);
e332a521 Christian Ehringfeld
}
return entity;
}

void EntityInspector::checkMetaProperties(QHash<QString, QMetaProperty>
2cded5d4 Christian Ehringfeld
&metaProperties, bool &ok, QHash<QString, Relation> &relations) {
f12670e9 Christian Ehringfeld
QString msg = "";
2cded5d4 Christian Ehringfeld
QMap<QString, QMetaProperty> metaPropertiesMap;
e332a521 Christian Ehringfeld
for (auto i = metaProperties.constBegin(); i != metaProperties.constEnd();
2cded5d4 Christian Ehringfeld
++i) {
metaPropertiesMap[i.key()] = i.value();
}
for (auto i = metaPropertiesMap.constBegin(); i != metaPropertiesMap.constEnd(); i++) {
e332a521 Christian Ehringfeld
QString typeName = QString(i.value().typeName());
if (!i.value().isWritable()) {
ok = false;
1bb76836 Christian Ehringfeld
msg += "Property " + i.key() + " is not writable!\n";
e332a521 Christian Ehringfeld
}
if (!i.value().isReadable()) {
ok = false;
1bb76836 Christian Ehringfeld
msg += "Property " + i.key() + " is not readable!\n";
e332a521 Christian Ehringfeld
}
if (typeName.contains("QSharedPointer") && !relations.contains(i.key())) {
ok = false;
1bb76836 Christian Ehringfeld
msg += "No relation defined for attribute " + i.key() + "!\n";
e332a521 Christian Ehringfeld
} else if (typeName.contains("QPointer")) {
ok = false;
msg += i.key() + " must use QSharedPointer.\n";
}
}
f12670e9 Christian Ehringfeld
this->logger->logMsg(msg, MsgType::CRITICAL);
e332a521 Christian Ehringfeld
}
93285804 Christian Ehringfeld
f12670e9 Christian Ehringfeld
bool EntityInspector::verifyRelations(Entity *&entity) {
e332a521 Christian Ehringfeld
bool ok = true;
auto metaProperties = EntityHelper::getMetaProperties(entity);
auto relations = entity->getRelations();
f12670e9 Christian Ehringfeld
QString msg = "";
this->checkMetaProperties(metaProperties, ok, relations);
2cded5d4 Christian Ehringfeld
QMap<QString, Relation> relationsMap;
for (auto i = relations.constBegin(); i != relations.constEnd(); i++) {
relationsMap[i.key()] = i.value();
}
for (auto i = relationsMap.constBegin(); i != relationsMap.constEnd(); ++i) {
f12670e9 Christian Ehringfeld
this->checkRelationTypos(i.key(), i.value(), ok);
e332a521 Christian Ehringfeld
if (!metaProperties.contains(i.key())) {
2cded5d4 Christian Ehringfeld
msg += i.key();
5f3c7a9c Christian Ehringfeld
ok = false;
e332a521 Christian Ehringfeld
} else {
auto metaProperty = metaProperties.value(i.key());
if (!QString(metaProperty.typeName()).contains("QSharedPointer")) {
f12670e9 Christian Ehringfeld
msg += "Property " + QString(metaProperty.name()) +
2cded5d4 Christian Ehringfeld
" must be a type like QList<QSharedPointer<T>> or simply QSharedPointer<T>.";
e332a521 Christian Ehringfeld
} else {
auto var = metaProperty.read(entity);
f12670e9 Christian Ehringfeld
bool rel = this->checkRelation(var, i.value(), metaProperty);
e332a521 Christian Ehringfeld
if (!rel) {
ok = false;
43457c84 Christian Ehringfeld
} else {
ea09b5be Christian Ehringfeld
this->checkRelationMappings(metaProperty, i.value(), ok, entity);
e332a521 Christian Ehringfeld
}
}
}
}
f12670e9 Christian Ehringfeld
if (!msg.isEmpty()) {
this->logger->logMsg(msg, MsgType::CRITICAL);
e332a521 Christian Ehringfeld
}
return ok;
}

f12670e9 Christian Ehringfeld
void EntityInspector::verifyTransientAttributes(Entity *&entity) {
e332a521 Christian Ehringfeld
auto metaProperties = EntityHelper::getMetaProperties(entity);
auto relations = entity->getRelations();
auto transientAttributes = entity->getTransientAttributes();
auto blobs = entity->getBLOBColumns();
f12670e9 Christian Ehringfeld
QString msg = "";
e332a521 Christian Ehringfeld
for (int i = 0; i < transientAttributes.size(); ++i) {
QString attr = transientAttributes.at(i);
if (!metaProperties.contains(attr)) {
f12670e9 Christian Ehringfeld
msg += "No transient attribute called " + attr + ".\n";
e332a521 Christian Ehringfeld
}
if (relations.contains(transientAttributes.at(i))) {
f12670e9 Christian Ehringfeld
msg += "A transient attribute should not be declared as relation: " +
2cded5d4 Christian Ehringfeld
attr + ".\n";
e332a521 Christian Ehringfeld
}
if (blobs.contains(attr)) {
f12670e9 Christian Ehringfeld
msg += "A transient attribute should not be declared as blob column: " + attr +
2cded5d4 Christian Ehringfeld
".\n";
e332a521 Christian Ehringfeld
}
}
f12670e9 Christian Ehringfeld
if (!msg.isEmpty()) {
this->logger->logMsg(msg, MsgType::WARNING);
e332a521 Christian Ehringfeld
}
}

bool EntityInspector::checkRelation(const QVariant &entity,
f12670e9 Christian Ehringfeld
const Relation &r, const QMetaProperty &property) const {
QString msg = "";
e332a521 Christian Ehringfeld
bool many = r.getType() == RelationType::MANY_TO_MANY
2cded5d4 Christian Ehringfeld
|| r.getType() == RelationType::ONE_TO_MANY;
e332a521 Christian Ehringfeld
QString propType = QString(property.type());
bool canConvertList = entity.canConvert<QVariantList>() || (many
2cded5d4 Christian Ehringfeld
&& propType.contains("QList"));
e332a521 Christian Ehringfeld
if ((many && !canConvertList)) {
f12670e9 Christian Ehringfeld
msg = "Relation type of " + r.getPropertyName() +
2cded5d4 Christian Ehringfeld
" must be MANY_TO_MANY or ONE_TO_MANY.\n Or you can change the attribute type to QSharedPointer<T>.\n";
e332a521 Christian Ehringfeld
} else if ((!many && canConvertList)) {
f12670e9 Christian Ehringfeld
msg = "Relation type of " + r.getPropertyName() +
2cded5d4 Christian Ehringfeld
" must be MANY_TO_ONE or ONE_TO_ONE.\n Or you can change the attribute type to QList<QSharedPointer<T>>.\n";
e332a521 Christian Ehringfeld
}
if (many && r.getType() == RelationType::ONE_TO_MANY
&& r.getMappedBy().isEmpty()) {
f12670e9 Christian Ehringfeld
msg += "Relation " + r.getPropertyName() +
2cded5d4 Christian Ehringfeld
" needs a mappedBy attribute of the foreign class.\n";
e332a521 Christian Ehringfeld
}
f12670e9 Christian Ehringfeld
if (!msg.isEmpty()) {
this->logger->logMsg(msg, MsgType::CRITICAL);
e332a521 Christian Ehringfeld
return false;
}
return true;
93285804 Christian Ehringfeld
}

5f3c7a9c Christian Ehringfeld
void EntityInspector::checkRelationTypos(const QString &name, const Relation &r,
2cded5d4 Christian Ehringfeld
bool &ok) {
5f3c7a9c Christian Ehringfeld
if (name != r.getPropertyName()) {
ok = false;
f12670e9 Christian Ehringfeld
this->logger->logMsg("Relation " + name + " has a typo.\n" + "Name " + name +
"and relation name " + r.getPropertyName() +
" are not equal.\n", MsgType::WARNING);
5f3c7a9c Christian Ehringfeld
}
}

ea09b5be Christian Ehringfeld
void EntityInspector::checkNotMappedByAttributes(int foundMappedBy, bool &ok,
2cded5d4 Christian Ehringfeld
const QString &propertyName, const QString &foreignEntity) {
ea09b5be Christian Ehringfeld
if (foundMappedBy == 0) {
this->logger->logMsg("Optional: The relation " + propertyName +
" is not mapped in foreign class " + foreignEntity +
". You could map it.\n", MsgType::INFO);
} else if (foundMappedBy > 1) {
this->logger->logMsg("The relation " + propertyName +
" is mapped several times (" +
QString::number(foundMappedBy) + ") by foreign class " + foreignEntity +
". You should map it only once!\n",
MsgType::WARNING);
ok = false;
}
}

void EntityInspector::checkRelationTypes(const Relation &r,
2cded5d4 Christian Ehringfeld
const Relation &foreign, bool &ok) {
ea09b5be Christian Ehringfeld
if (r.getType() == RelationType::ONE_TO_ONE
&& foreign.getType() != RelationType::ONE_TO_ONE) {
ok = false;
this->logRelationTypeErrorMsg("ONE_TO_ONE", r, foreign);
} else if (r.getType() == RelationType::MANY_TO_MANY
&& foreign.getType() != RelationType::MANY_TO_MANY) {
this->logRelationTypeErrorMsg("MANY_TO_MANY", r, foreign);
ok = false;
} else if (r.getType() == RelationType::MANY_TO_ONE
&& foreign.getType() != RelationType::ONE_TO_MANY) {
this->logRelationTypeErrorMsg("ONE_TO_MANY", r, foreign);
ok = false;
}
}

void EntityInspector::logRelationTypeErrorMsg(const QString &type,
2cded5d4 Christian Ehringfeld
const Relation &r, const Relation &foreign) {
ea09b5be Christian Ehringfeld
this->logger->logMsg("Relation type of foreign relation " +
foreign.getPropertyName() +
" must be of type " + type + "! Foreign property name is called " +
r.getPropertyName() + ".",
MsgType::CRITICAL);
}

void EntityInspector::analyzeForeignRelations(const Relation &r,
2cded5d4 Christian Ehringfeld
const Entity *const entity, const Entity *const foreignInstance, bool &ok,
int &foundMappedBy, bool &foundForeignMappedRelation, bool &bothSidedMappedBy) {
ea09b5be Christian Ehringfeld
auto foreignRelations = EntityHelper::getRelationProperties(foreignInstance);
auto superClasses = EntityHelper::superClasses(entity, true);
QStringList classNames = QStringList {EntityHelper::getClassName(entity)};
for (int s = 0; s < superClasses.size(); ++s) {
classNames.append(superClasses.at(s)->className());
}
for (auto i = foreignRelations.constBegin(); i != foreignRelations.constEnd();
2cded5d4 Christian Ehringfeld
++i) {
ea09b5be Christian Ehringfeld
if (r.getMappedBy().isEmpty()
&& i.key().getMappedBy() == r.getPropertyName()) {
for (int x = 0; x < classNames.size(); ++x) {
if (QString(i.value().typeName()).contains(classNames.at(x))) {
++foundMappedBy;
this->checkRelationTypes(r, i.key(), ok);
break;
}
}
} else if (!r.getMappedBy().isEmpty()
&& r.getMappedBy() == i.key().getPropertyName()) {
foundForeignMappedRelation = true;
this->checkRelationTypes(r, i.key(), ok);
if (r.getPropertyName() == i.key().getMappedBy()) {
bothSidedMappedBy = true;
}
break;
}
}
}


43457c84 Christian Ehringfeld
void EntityInspector::checkRelationMappings(QMetaProperty &property,
2cded5d4 Christian Ehringfeld
const Relation &r, bool &ok, Entity *&entity) {
43457c84 Christian Ehringfeld
QString foreignEntityName = EntityInstanceFactory::extractEntityType(
2cded5d4 Christian Ehringfeld
property.typeName());
43457c84 Christian Ehringfeld
auto foreignInstance = EntityInstanceFactory::createInstance(foreignEntityName);
if (foreignInstance) {
int foundMappedBy = 0;
ea09b5be Christian Ehringfeld
bool foundForeignMappedRelation = false, bothSidedMappedBy = false;
this->analyzeForeignRelations(r, entity, foreignInstance, ok, foundMappedBy,
foundForeignMappedRelation, bothSidedMappedBy);
43457c84 Christian Ehringfeld
if (r.getMappedBy().isEmpty()) {
ea09b5be Christian Ehringfeld
this->checkNotMappedByAttributes(foundMappedBy, ok, r.getPropertyName(),
foreignEntityName);
43457c84 Christian Ehringfeld
} else if (!foundForeignMappedRelation) {
f12670e9 Christian Ehringfeld
this->logger->logMsg("Relation " + r.getPropertyName() +
" with mappedBy attribute " +
r.getMappedBy() + " has no mapped relation in " + foreignEntityName +
" class!\n", MsgType::CRITICAL);
43457c84 Christian Ehringfeld
ok = false;
ea09b5be Christian Ehringfeld
} else if (bothSidedMappedBy) {
this->logger->logMsg("Relation " + r.getPropertyName() +
" with mappedBy attribute " +
r.getMappedBy() + " is also mappedBy in " + foreignEntityName +
" class!\n", MsgType::CRITICAL);
ok = false;
43457c84 Christian Ehringfeld
}
153c0e85 Christian Ehringfeld
delete foreignInstance;
foreignInstance = nullptr;
43457c84 Christian Ehringfeld
} else {
f12670e9 Christian Ehringfeld
this->logger->logMsg("Can't create object for property/relation " +
r.getPropertyName() +
"\n" + "Classname: " + foreignEntityName + "\n" + "Is the class registered?\n",
MsgType::CRITICAL);
43457c84 Christian Ehringfeld
ok = false;
}
}

f12670e9 Christian Ehringfeld
bool EntityInspector::checkPrimaryKey(Entity *&entity) {
e332a521 Christian Ehringfeld
QString pk = entity->getPrimaryKey();
auto metaprops = EntityHelper::getMetaProperties(entity);
bool ok = true;
if (!metaprops.contains(pk)) {
ok = false;
f12670e9 Christian Ehringfeld
this->logger->logMsg("Property " + pk +
" for primary key not exists. Please check your getPrimaryKey() method!\n",
MsgType::CRITICAL);
e332a521 Christian Ehringfeld
}
a873a3ba Christian Ehringfeld
if(metaprops.size() <= 1) {
ok = false;
this->logger->logMsg("Entity has only one attribute. Please add attributes. Otherwise you can run into problems.",
MsgType::CRITICAL);
}
e332a521 Christian Ehringfeld
return ok;
}

f12670e9 Christian Ehringfeld
void EntityInspector::verifyBlobAttributes(Entity *&entity) {
e332a521 Christian Ehringfeld
auto metaprops = EntityHelper::getMetaProperties(entity);
auto blobs = entity->getBLOBColumns();
f12670e9 Christian Ehringfeld
QString msg = "";
e332a521 Christian Ehringfeld
for (int i = 0; i < blobs.size(); ++i) {
QString name = blobs.at(i);
if (!metaprops.contains(name)) {
f12670e9 Christian Ehringfeld
msg += "For blob column " + name + " no property exists.\n";
e332a521 Christian Ehringfeld
}
}
f12670e9 Christian Ehringfeld
this->logger->logMsg(msg, MsgType::WARNING);
e332a521 Christian Ehringfeld
}

f12670e9 Christian Ehringfeld
void EntityInspector::initLogger(const MsgType msgType) {
this->logger = new Logger(QDir::currentPath() + "/entity.log", msgType);
e332a521 Christian Ehringfeld
}