Изменение длинны поля в Windchill

Самым популярных вопросом по кастомизации Windchill остается изменение допустимой длинны значения атрибута бизнес объекта в Windchill.Длинна поля меняеться с помощью пакета wt.introspection. Описание длинны атрибута храниться в свойстве UpperLimit модели RationRose. Это значение может быть изменено записью ограничения на длину в кастомизационный файл.

В общем случае нужно выполнить следующие шаги:


1. Определяемся длину какого атрибута мы хотим поменять.

2. Добавляем запись об ограничении в кастомизационный файл.
3. Сгенерировать SQL скрипт.
4. Проверить изменения.
5. Выполнить служебные скрипты.
6. Сделать рестарт.

Давайте рассмотрим пример изменения ограничения длинны поля «Наименование» у документа, ему соответствует класс wt.doc.WTDocumentMaster и мы хотим задать ограничение в 350 символов( в зависимости от кодировке в базе данных цифра может быть в 2 раза больше).
По умолчанию кастомизационные файлы находяться в каталоге $(wt.home)\wtCustom, как написано в свойстве wt.generation.custom.dir. Создайте директорию если она не существует.
1. Определяемся что же нужно прописать в кастомизационный класс:
a. Из винчил шелла нужно выполнить команду:
infoReport wt.doc.WTDocumentMaster

b. Потом найти свойство WTIntrospector.UPPER_LIMIT для атрибута «name» (по русски наименование) по умолчанию должно быть:
getValue( WTIntrospector.UPPER_LIMIT ): 60

c. Теперь заполняем кастомизационный файл:
? Создаем файл по точно такому пути <Windchill>\wtCustom\wt\doc\docModel.properties.
? И добавляем в него одну строчку
WTDocumentMaster.name.UpperLimit=350
# ignore multi-byte database character sets when setting value

3. Генерируем новые java классы и SQL скрипты выполняя команду из windchill shell:
ant -f <Windchill>\bin\tools.xml custom_column -Dgen.input=wt.doc

4. Проверяем изменения:
a. Снова выполняем команду infoReport wt.doc.WTDocumentMaster
и находим свойство getValue( WTIntrospector.UPPER_LIMIT ): 350
здесь должно быть новое значение.

b. Следующий файл должен обновиться (дата и размер):
<Windchill>\codebase\wt\doc\WTDocumentMaster.ClassInfo.ser

5. Выполняем сгенерированные скрипты:

a. Выполните команду UpgradeManager.bat -cs, как описано в Windchill Upgrade Guide.
b. Посмотрите сгенерированные скрипты и при необходимости выполните их.
Caution
Не выполняйте SQL запросы в необходимости и правильности которых вы не уверены.

c. Если все таки в базе значение не поменялось, но в классах все ок. Заходим в базу через enterprice manager находим таблицу WTDOCUMENTNASTER грохаем индекс по name меняем длину столбца name создаем индекс из скрипта sql который лежит в db/sql. Но это вроде бы нужно было делать только в 8й версии в 9й все ок.

Бонусная новость от меня.
Компания ptc не на шутку испугалась проблем с безопасностью в PDM Windchill. Оказываеться пакет java.io используетсья более чем в 2500-3000 java классах Windchill. Эта программная библиотека используется для работы с локальной файловой системой. Т.е позволяет выполнять всевозможные действия с папками и файлами. А проблема оказалась в том что обладая определенными навыками можно скачать либо закачать любой файл с сервера Windchill вызывая java классы Windchill. Так же Windchill 9 уязвим для XSS атак, связанных с перенаправлением ссылок на сервере и как следствие не санкционированный доступ. Часть описанных проблем уже исправлена в Windchill 10, но далеко не все, потому что проверить нужно достаточно много файлов. Я пару таких команд нашел, но публиковать не буду иначе куча винчилов дилетантами порушиться.

Сюда же одно полезное замечание. Если вы занимаетесь кастомизацией винчил наверняка пользуетесь декомпилятором. И частенько декомпилируешь класс а в нем вызов это ва же класса как например

com.ptc.core.meta.type.admin.common.impl.TypeAdminServiceIfcFwd- класс используется для программного создания легковесного типа.
Смотрим метод createTypeNode а внем строчка
return ((TypeAdminServiceIfc)getManager()).
createTypeNode(typedefinitionnodeview, locale);
TypeAdminServiceIfcFwd реализует абстрактный класс TypeAdminServiceIfc
Ну и программист тут же смущается вроде как где же бизнеслогика ведь метод createTypeNode вызывает сам себя.
Сабака зарыта здесь. Гуру программисты Windchill используют паттерн инвенсшн оф контролл который позволяет отделить реализацию от бизнес- логики.
Если выполнить поиск по wt.properties найдем строчку

wt.services.service.660=com.ptc.core.meta.type.admin.common.impl.TypeAdminServiceIfc/com.ptc.core.meta.type.admin.server.impl.StandardTypeAdminService

StandardTypeAdminService- java класс который инкапсулирует всю бизнес логику работы с бизнес обьектами.

И в нем находи уже совсем не хилую реализацию метода( декомпиляцию выполнил jad ) достаточно качественно:

public TypeDefinitionNodeView createTypeNode(String s, TypeDefinitionNodeView typedefinitionnodeview, Locale locale)
throws RemoteException, NotAuthorizedException, WTContainerException, WTException
{
TypeDefinitionNodeView typedefinitionnodeview1 = typedefinitionnodeview;
if(s == null)
s = TypeDomainHelper.getExchangeDomain();
if(isModeledType(typedefinitionnodeview1))
{
String as[] = {
typedefinitionnodeview1.getName()
};
throwException(new WTContainerException(«com.ptc.core.meta.type.admin.server.impl.implResource», «ex08», as));
} else
{
String s1 = typedefinitionnodeview1.getName();
boolean flag = false;
String s4 = getNameFromFullyQualifiedTypeName(s1);
String s6 = getDomainFromFullyQualifiedTypeName(s1);
if(s6.equals(«»))
{
s6 = s;
s1 = (new StringBuilder()).append(s6).append(«.»).append(s4).toString();
flag = true;
}
if((s6.equals(«com.ptc») || s6.startsWith(«com.ptc.»)) && !s.equals(«com.ptc») && !s.startsWith(«com.ptc.»))
throwException(new WTContainerException(«com.ptc.core.meta.type.admin.server.impl.implResource», «ex04», null));
String s9 = TypeDomainHelper.getTypeNameForCreate(s4, s6);
if(s9 == null || !s9.equals(s1))
{
String as3[] = {
s6
};
throwException(new WTContainerException(«com.ptc.core.meta.type.admin.server.impl.implResource», «ex05», as3));
}
checkAccess(s1, AccessPermission.CREATE);
LogicalIdentifierFactory.validateTypeName(s1);
try
{
typedefinitionnodeview1.setName(s1);
}
catch(WTPropertyVetoException wtpropertyvetoexception)
{
if(flag)
throwAppDomainException(s6, s1.length());
throwException(new WTException(wtpropertyvetoexception));
}
if(typedefinitionnodeview1.getParentID() != null)
{
TypeDefinition typedefinition = (TypeDefinition)PersistenceHelper.manager.refresh(typedefinitionnodeview1.getParentID());
String s7 = TypeDomainHelper.getDomain(typedefinition.getName());
if(!TypeDomainHelper.isAssociatedWith(typedefinitionnodeview1.getName(), s7, true, false))
{
String as2[] = {
typedefinitionnodeview1.getName()
};
throwException(new WTContainerException(«com.ptc.core.meta.type.admin.server.impl.implResource», «ex02», as2));
}
}
if(typedefinitionnodeview1.getLogicalIdentifier() != null)
{
try
{
Class.forName(typedefinitionnodeview1.getLogicalIdentifier());
String as1[] = {
typedefinitionnodeview1.getLogicalIdentifier()
};
throwException(new WTContainerException(«com.ptc.core.meta.type.admin.server.impl.implResource», «ex06», as1));
}
catch(ClassNotFoundException classnotfoundexception)
{
LOG.trace(classnotfoundexception.getLocalizedMessage(), classnotfoundexception);
}
LogicalIdentifierFactory.validateLogicalIdentifier(typedefinitionnodeview1.getLogicalIdentifier());
}
}
String s2 = s;
if(s2 == null)
s2 = TypeDomainHelper.getExchangeDomain();
String s3 = typedefinitionnodeview.getName();
LogicalIdentifierFactory.validateTypeName(s3);
LogicalIdentifierFactory.validateLogicalIdentifier(typedefinitionnodeview.getLogicalIdentifier());
String s5 = getNameFromFullyQualifiedTypeName(s3);
String s8 = getDomainFromFullyQualifiedTypeName(s3);
if(s8.equals(«»))
s8 = s2;
String s10 = TypeDomainHelper.getTypeNameForCreate(s5, s8);
if(s10 == null || !s10.equals((new StringBuilder()).append(s8).append(«.»).append(s5).toString()))
{
String as4[] = {
s8
};
throwException(new WTContainerException(«com.ptc.core.meta.type.admin.server.impl.implResource», «ex05», as4));
}
String s11 = getDomainFromFullyQualifiedTypeName(s10);
if((s11.equals(«com.ptc») || s11.startsWith(«com.ptc.»)) && (s == null || !s.equals(«com.ptc») && !s.startsWith(«com.ptc.»)))
throwException(new WTContainerException(«com.ptc.core.meta.type.admin.server.impl.implResource», «ex04», null));
if(!TypeDomainHelper.isModifiableByCurrentUser(s10))
{
Object aobj[] = {
SessionHelper.manager.getPrincipal().getName(), AccessPermission.CREATE.getDisplay(), typedefinitionnodeview.getName()
};
AccessControlHelper.manager.emitAccessEvent(«NOT_AUTHORIZED», null, AccessPermission.CREATE, new WTMessage(wt/access/accessResource.getName(), «8», aobj));
String as5[] = {
s10
};
throwException(new NotAuthorizedException(null, «com.ptc.core.meta.type.admin.server.impl.implResource», «ex01», as5));
}
if(typedefinitionnodeview.getParentID() != null)
{
TypeDefinition typedefinition1 = (TypeDefinition)PersistenceHelper.manager.refresh(typedefinitionnodeview.getParentID());
String s12 = TypeDomainHelper.getDomain(typedefinition1.getName());
if(!TypeDomainHelper.isAssociatedWith(s10, s12, true, false))
{
String as6[] = {
s10
};
throwException(new WTContainerException(«com.ptc.core.meta.type.admin.server.impl.implResource», «ex02», as6));
}
}
TypeDefinition typedefinition2 = TypeDefinitionObjectsFactory.newTypeDefinition(typedefinitionnodeview);
try
{
if(typedefinition2 instanceof WTTypeDefinition)
((WTTypeDefinition)typedefinition2).setName(s10);
}
catch(WTPropertyVetoException wtpropertyvetoexception1)
{
throwException(new WTException(wtpropertyvetoexception1));
}
String s13 = theTypeManagementDBService.createTypeDefinition(typedefinition2);
TypeDefinitionDefaultView typedefinitiondefaultview = theAdminTypeDefinitionCache.getTypeDefinition(s13, true);
if(typedefinitiondefaultview == null)
{
LOG.info(«createTypeNode — null created node.»);
return null;
} else
{
return typedefinitiondefaultview.toTypeDefinitionNodeView();
}
}

Добавить комментарий