기본 사용자 정의 > Windchill Customization Basics > Getting Started With Windchill Customization > Creating a UI > Pet Information Page
  
Pet Information Page
Wiring the Pet table into Site > Utilities
At this point, acme.pet.table is accessible, but requires the user to specify the URL manually. Pet is not WTContained, so a logical place to wire in the table is under Site > Utilities.
1. The site utilities or managed by codebase/netmarkets/jsp/object/commonUtilities.jspf, a Windchill-delivered and Windchill-managed file. This file should not be updated in place; rather, it should be handled by the “safe area” mechanism.
a. Create the following two directory structures under load point:
wtSafeArea/ptcOrig/codebase/netmarkets/jsp/object
wtSafeArea/siteMod/codebase/netmarkets/jsp/object
Copy commonUtilities.jspf to both directories just created above.
2. Edit wtSafeArea/siteMod/codebase/netmarkets/jsp/object as follows to add the items in bold:
a. After <%@ page import="com.ptc.netmarkets.object.objectResource"%> add: <%@ page import="com.acme.acmeResource"%>
<%@ page import="com.ptc.netmarkets.object.objectResource"%>
<%@ page import="com.acme.acmeResource"%>
b. After private static final String ENTERPRISE_RESOURCE = "wt.enterprise.enterpriseResource"; add private static final String ACME_RESOURCE = "com.acme.acmeResource";
<%! private static final String OBJECT_CONFIG_RESOURCE =
"com.ptc.netmarkets.object.objectResource";
private static final String ENTERPRISE_RESOURCE =
"wt.enterprise.enterpriseResource";
private static final String ACME_RESOURCE = "com.acme.acmeResource";
c. After ResourceBundle enterpriseRb = ResourceBundle.getBundle(ENTERPRISE_RESOURCE, localeBean.getLocale()); add ResourceBundle acmeRb = ResourceBundle.getBundle(ACME_RESOURCE, localeBean.getLocale());
ResourceBundle objectRb = ResourceBundle.getBundle
(OBJECT_CONFIG_RESOURCE, localeBean.getLocale());
ResourceBundle enterpriseRb = ResourceBundle.getBundle
(ENTERPRISE_RESOURCE, localeBean.getLocale());
ResourceBundle acmeRb = ResourceBundle.getBundle(
ACME_RESOURCE, localeBean.getLocale());
d. After "PERSONAL_CABINETS” , add "PET_ADMINISTRATION" ,
String [] knownUtilities={"AUDITING_PURGE",
"AUDITING_LICENSE_USAGE",
"AUDITING_ORGANIZATION_USAGE",
"AUDITING_SECURITY_REPORT_QUERIES",
"AUDITING_SECURITY_REPORTS",
"CALENDAR_MANAGEMENT",
"CLASSIFICATION_ADMINISTRATOR",
"SCMI_ADAPTER_ADMINISTRATOR",
"SCMI_ADMINISTRATOR",
"CONFIGURATION_FILE_GENERATOR",
"ESI_TRANSACTION_ADMIN",
"REPLICATION_ADMINISTRATOR",
"CCS_MANAGER",
"IMPORT_EXPORT",
"INFO_ENGINE" ,
"NUMBERING_SCHEMES",
"VERSIONING_SCHEMES",
"LIFE_CYCLE_ADMIN",
"ESI_DISTRIBUTION_TARGET_ADMIN",
"OPTEGRA_GATEWAY",
"RULES_ADMINISTRATION",
"PACKAGES_MAPPING_MANAGER",
"PARTICIPANT_ADMINISTRATION",
"PERSONAL_CABINETS" ,
"PET_ADMINISTRATION",
e. After the if (wvs_enabled ) { block add linkDatum.put("PET_ADMINISTRATION.isUtilityInstalled", "Yes");
if (wvs_enabled ) {
linkDatum.put("CAD_AGENT.isUtilityInstalled" , "Yes" );
linkDatum.put("PRODUCT_VIEW.isUtilityInstalled" , "Yes" );
linkDatum.put("PUBLISH_MONITOR.isUtilityInstalled" , "Yes" );
linkDatum.put("PUBLISH_SCHEDULER.isUtilityInstalled" , "Yes" );
linkDatum.put("PUBLISH_THB_CONTROL.isUtilityInstalled" , "Yes" );
}

linkDatum.put("PET_ADMINISTRATION.isUtilityInstalled", "Yes");
f. After linkDatum.put("AUDITING_SECURITY_REPORTS.isAuditUtility" , "Yes" ); add // set ACME utility flag. Define only if the utility is considered an ACME utility linkDatum.put("PET_ADMINISTRATION.isACMEUtility", "Yes");
// set audit utility flag. Define only if the utility is considered an
// auditing utility
linkDatum.put("AUDITING_PURGE.isAuditUtility" , "Yes" );
linkDatum.put("AUDITING_ORGANIZATION_USAGE.isAuditUtility" , "Yes" );
linkDatum.put("AUDITING_LICENSE_USAGE.isAuditUtility" , "Yes" );
linkDatum.put("AUDITING_SECURITY_REPORT_QUERIES.isAuditUtility", "Yes" );
linkDatum.put("AUDITING_SECURITY_REPORTS.isAuditUtility" , "Yes" );

// set ACME utility flag. Define only if the utility is
considered an ACME utility
linkDatum.put("PET_ADMINISTRATION.isACMEUtility", "Yes"
);
g. After linkDatum.put("PERSONAL_CABINETS.idText" , linkBean.getLinkID(null,"textLink:deletedUsersCabinets") ); add linkDatum.put("PET_ADMINISTRATION.idText" , linkBean.getLinkID(null,"textLink:petAdmin") );
// The value to use for id. An entry is required for all known utilities
linkDatum.put("AUDITING_PURGE.idText" , linkBean.getLinkID(null,"textLink:auditingPurge") );
linkDatum.put("AUDITING_ORGANIZATION_USAGE.idText" , linkBean.getLinkID(null,"textLink:auditingOrgUsage") );
linkDatum.put("AUDITING_LICENSE_USAGE.idText" , linkBean.getLinkID(null,"textLink:auditingLicenseUsage") );
linkDatum.put("AUDITING_SECURITY_REPORT_QUERIES.idText" , linkBean.getLinkID(null,"textLink:auditingReportQueries") );
linkDatum.put("AUDITING_SECURITY_REPORTS.idText" , linkBean.getLinkID(null,"textLink:auditingReports") );
linkDatum.put("CAD_AGENT.idText" , linkBean.getLinkID(null,"textLink:cadAgentAdmin") );
linkDatum.put("CALENDAR_MANAGEMENT.idText" , linkBean.getLinkID(null,"textLink:calendarManagement") );
linkDatum.put("CLASSIFICATION_ADMINISTRATOR.idText" , linkBean.getLinkID(null,"textLink:classificationAdministrator") );
linkDatum.put("CONFIGURATION_FILE_GENERATOR.idText" , linkBean.getLinkID(null,"textLink:configurationFileGenerator") );
linkDatum.put("ESI_DISTRIBUTION_TARGET_ADMIN.idText" , linkBean.getLinkID(null,"textLink:ESI_DISTRIBUTION_TARGET_ADMIN") );
linkDatum.put("ESI_TRANSACTION_ADMIN.idText" , linkBean.getLinkID(null,"textLink:ESI") );
linkDatum.put("EXTERNAL_STORAGE.idText" , linkBean.getLinkID(null,"textLink:externalStorageAdmin") );
linkDatum.put("IMPORT_EXPORT.idText" , linkBean.getLinkID(null,"textLink:importExportAdmin") );
linkDatum.put("PACKAGES_MAPPING_MANAGER.idText" , linkBean.getLinkID(null,"textLink:packageMappingManager") );
linkDatum.put("INFO_ENGINE.idText" , linkBean.getLinkID(null,"textLink:infoEngineAdmin") );
linkDatum.put("LIFE_CYCLE_ADMIN.idText" , linkBean.getLinkID(null,"textLink:lifeCycleTemplateAdmin") );
linkDatum.put("NUMBERING_SCHEMES.idText" , linkBean.getLinkID(null,"textLink:numberingSchemesAdmin") );
linkDatum.put("POLICY_ADMINISTRATOR.idText" , linkBean.getLinkID(null,"textLink:policyAdmin") );
linkDatum.put("PERSONAL_CABINETS.idText" , linkBean.getLinkID(null,"textLink:deletedUsersCabinets") );
linkDatum.put("PET_ADMINISTRATION.idText" , linkBean.getLinkID(null,"textLink:petAdmin") );
h. After linkDatum.put("VIEW_NETWORK.pageLoc" , viewAction.getActionUrl(actionBean, linkBean, objectBean, localeBean, urlFactoryBean,nmcontext, sessionBean,request)); add //ACME pageLocs linkDatum.put("PET_ADMINISTRATION.pageLoc", NetmarketURL.convertToShellURL("ptc1/comp/acme.pet.table"));
//We need to get the locale specific link for the network admin .

NmAction viewAction = NmActionServiceHelper.service.getAction
("view","list");
linkDatum.put("VIEW_NETWORK.pageLoc"
, viewAction.getActionUrl(actionBean, linkBean,
objectBean, localeBean,
urlFactoryBean,nmcontext, sessionBean,request));

//ACME pageLocs
linkDatum.put("PET_ADMINISTRATION.pageLoc", NetmarketURL.convertToShellURL("ptc1/comp/acme.pet.table"));
i. After linkDatum.put("NUMBERING_SCHEMES.urlPrarms" ,"'NumberingSchemes','resizable=yes,scrollbars=yes,menubar=yes,toolbar=yes,location=yes,status=yes'"); add linkDatum.put("PET_ADMINISTRATION.urlPrarms" ,"'PetAdmin','resizable=yes,scrollbars=yes,menubar=yes,toolbar=yes,location=yes,status=yes'" );
linkDatum.put("ESI_TRANSACTION_ADMIN.urlPrarms","'ESITransaction','
directories=no,location=no,menubar=no,scrollbars=yes,status=yes,
toolbar=no,resizable=yes,height=1000,width=1400'" );

linkDatum.put("EXTERNAL_STORAGE.urlPrarms"
,"'ExternalStorage','resizable=yes,scrollbars=yes,menubar=no,
toolbar=no,location=no,status=yes,height=455,width=640'" );
linkDatum.put("IMPORT_EXPORT.urlPrarms"
,"'_blank','resizable=yes,scrollbars=yes,menubar=no,
toolbar=no,location=no,
status=yes,height=455,width=640'");
linkDatum.put("PACKAGES_MAPPING_MANAGER.urlPrarms"
,"'_blank','resizable=yes,scrollbars=yes,menubar=no,
toolbar=no,location=no,
status=yes,height=500,width=880'");
linkDatum.put("INFO_ENGINE.urlPrarms"
,"'InfoEngine','resizable=yes,scrollbars=yes,menubar=yes,
toolbar=yes,
location=yes,status=yes'" );
linkDatum.put("LIFE_CYCLE_ADMIN.urlPrarms"
,"'LifeCycleAdmin','resizable=yes,scrollbars=yes,menubar=yes,
toolbar=yes,
location=yes,status=yes'");
linkDatum.put("NUMBERING_SCHEMES.urlPrarms"
,"'NumberingSchemes','resizable=yes,scrollbars=yes,menubar=yes,
toolbar=yes,
location=yes,status=yes'");
linkDatum.put("PET_ADMINISTRATION.urlPrarms"
,"'PetAdmin','resizable=yes,scrollbars=yes,menubar=yes,
toolbar=yes,
location=yes,status=yes'" );
j. After linkDatum.put("PERSONAL_CABINETS.linkText" ,objectRb.getString(objectResource.PERSONAL_CABINETS)); add linkDatum.put("PET_ADMINISTRATION.linkText" ,acmeRb.getString(acmeResource.PET_ADMINISTRATION));
linkDatum.put("EXTERNAL_STORAGE.linkText" ,objectRb.getString(objectResource.EXTERNAL_STORAGE));
linkDatum.put("IMPORT_EXPORT.linkText"
,objectRb.getString(objectResource.IMPORT_EXPORT));
linkDatum.put("PACKAGES_MAPPING_MANAGER.linkText"
,objectRb.getString(objectResource.PACKAGES_MAPPING_MANAGER));
linkDatum.put("INFO_ENGINE.linkText"
,objectRb.getString(objectResource.INFO_ENGINE));
linkDatum.put("LIFE_CYCLE_ADMIN.linkText"
,objectRb.getString(objectResource.LIFE_CYCLE_ADMIN));
linkDatum.put("NUMBERING_SCHEMES.linkText"
,objectRb.getString(objectResource.NUMBERING_SCHEMES));
linkDatum.put("PERSONAL_CABINETS.linkText"
,objectRb.getString(objectResource.PERSONAL_CABINETS));
linkDatum.put("PET_ADMINISTRATION.linkText"
,acmeRb.getString(acmeResource.PET_ADMINISTRATION));
k. After linkDatum.put("PERSONAL_CABINETS.linkDesc" ,objectRb.getString(objectResource.PERSONAL_CABINETS_DESCRIPTION)); add linkDatum.put("PET_ADMINISTRATION.linkDesc" ,acmeRb.getString(acmeResource.PET_ADMINISTRATION_DESCRIPTION));
linkDatum.put("EXTERNAL_STORAGE.linkDesc"
,objectRb.getString(objectResource.EXTERNAL_STORAGE_DESCRIPTION));
linkDatum.put("IMPORT_EXPORT.linkDesc"
,objectRb.getString(objectResource.IMPORT_EXPORT_DESCRIPTION));
linkDatum.put("PACKAGES_MAPPING_MANAGER.linkDesc"
,objectRb.getString(objectResource.PACKAGES_MAPPING_MANAGER_DESCRIPTION));
linkDatum.put("INFO_ENGINE.linkDesc"
,objectRb.getString(objectResource.INFO_ENGINE_DESCRIPTION));
linkDatum.put("LIFE_CYCLE_ADMIN.linkDesc"
,objectRb.getString(objectResource.LIFE_CYCLE_ADMIN_DESCRIPTION));
linkDatum.put("NUMBERING_SCHEMES.linkDesc"
,objectRb.getString(objectResource.NUMBERING_SCHEMES_DESCRIPTION));
linkDatum.put("PERSONAL_CABINETS.linkDesc"
,objectRb.getString(objectResource.PERSONAL_CABINETS_DESCRIPTION));
linkDatum.put("PET_ADMINISTRATION.linkDesc"
,acmeRb.getString(acmeResource.PET_ADMINISTRATION_DESCRIPTION));
l. Replace
objectRb.getString(objectResource.AUDITING_ADMINISTRATION)};
boolean [] systemHeader={true,false,false};
boolean [] auditHeader={false,false,true};
with
objectRb.getString(objectResource.AUDITING_ADMINISTRATION),
acmeRb.getString(acmeResource.ACME_ADMINISTRATION)};
boolean [] systemHeader={true,false,false,false};
boolean [] auditHeader={false,false,true,false};
boolean [] acmeHeader={false,false,false,true};
m. After the //Match audit/nonaudit section add //Match acme/noacme String isACME = knownUtilities[i].concat(".isACMEUtility"); if (linkDatum.containsKey(isACME)!=acmeHeader[currentHeader]) { continue;
//Match audit/nonaudit
String isAudit = knownUtilities[i].concat(".isAuditUtility");
if (linkDatum.containsKey(isAudit)!=auditHeader[currentHeader]) {
continue;
}
//Match acme/noacme
String isACME = knownUtilities[i].concat(".isACMEUtility");
if (linkDatum.containsKey(isACME)!=acmeHeader[currentHeader]) {
continue;
n. After <% } else if ("RULES_ADMINISTRATION".equals(knownUtilities[i])) { %> href="<%=pageLoc%>" add <% } else if ("PET_ADMINISTRATION".equals(knownUtilities[i])) { %> href="<%=pageLoc%>"
<% } else if ("RULES_ADMINISTRATION".equals(knownUtilities[i])) { %>
href="<%=pageLoc%>"
<% } else if ("PET_ADMINISTRATION".equals(knownUtilities[i])) { %>
href="<%=pageLoc%>"
<% }
3. Enable PET_ADMINISTRATION
a. Create the following two directory structures under load point:
wtSafeArea/ptcOrig/codebase/netmarkets/jsp/site
wtSafeArea/siteMod/codebase/netmarkets/jsp/site
b. Copy listUtilities.jspf to both directories just created above.
c. Edit wtSafeArea/siteMod/codebase/netmarkets/jsp/site/listUtilities.jsp, appending (after line 67) the following to the enabled:
showUtility.put("PET_ADMINISTRATION" , "Enable");
4. Deploy the site modifications: ant -f bin/swmaint.xml installSiteChanges
5. Create the imported acmeResource as shown
package com.acme;

import wt.util.resource.*;

@RBUUID("com.acme.acmeResource")
public class acmeResource extends WTListResourceBundle {
@RBEntry("ACME Administration")
public static final String ACME_ADMINISTRATION = "acme_administration";

@RBEntry("Pet Administration")
public static final String PET_ADMINISTRATION = "pet_administration";

@RBEntry("CRUD opererations for pets")
public static final String PET_ADMINISTRATION_DESCRIPTION =
"pet_administration_description";
}
6. Start/restart Windchill.
7. Site > Utilities should incorporate ACME Administration, as shown
Pet Information Page
The table currently shows an “i” for an info page (for Stimpy), but the information page has not been created yet (clicking the “i” will result in an error).
1. Create the primary builder for the information page. Complete source follows:
package com.acme.mvc.builders;

import wt.util.WTException;

import com.ptc.jca.mvc.builders.DefaultInfoComponentBuilder;
import com.ptc.mvc.components.ComponentBuilder;
import com.ptc.mvc.components.ComponentId;
import com.ptc.mvc.components.ComponentParams;
import com.ptc.mvc.components.InfoConfig;
import com.ptc.mvc.components.TypeBased;

@ComponentBuilder(ComponentId.INFOPAGE_ID)
@TypeBased("com.acme.Pet")
public class PetInfoBuilder extends DefaultInfoComponentBuilder {
@Override
protected InfoConfig buildInfoConfig(final ComponentParams params)
throws WTException {
final InfoConfig info = getComponentConfigFactory().newInfoConfig();
info.setTabSet("petDetails");
return info;
}
}
2. Define the petDetails tab set by creating its action model (in config/actions/Pet-actionmodels.xml).
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE actionmodels SYSTEM 'actionmodels.dtd'>
<actionmodels>
<model name="petDetails">
<action name="primaryAttributes" type="object"/>
<action name="attachments" type="object"/>
</model>
</actionmodels>
3. Define the primaryAttributes.
package com.acme.mvc.builders;

import wt.util.WTException;

import com.acme.Pet;
import com.ptc.core.ui.resources.ComponentType;
import com.ptc.jca.mvc.components.AbstractAttributesComponentBuilder;
import com.ptc.jca.mvc.components.JcaAttributeConfig;
import com.ptc.jca.mvc.components.JcaGroupConfig;
import com.ptc.mvc.components.AttributePanelConfig;
import com.ptc.mvc.components.ComponentBuilder;
import com.ptc.mvc.components.ComponentConfigFactory;
import com.ptc.mvc.components.ComponentId;
import com.ptc.mvc.components.ComponentParams;
import com.ptc.mvc.components.TypeBased;

@ComponentBuilder("primaryAttributes")
@TypeBased("com.acme.Pet")
public class PetInfoAttributesBuilder extends
AbstractAttributesComponentBuilder {
@Override
protected AttributePanelConfig buildAttributesComponentConfig
(final ComponentParams params)
throws WTException {
final ComponentConfigFactory factory = getComponentConfigFactory();

final AttributePanelConfig panel; {
panel = factory.newAttributePanelConfig(ComponentId.ATTRIBUTE_PANEL_ID);
panel.setComponentType(ComponentType.WIZARD_ATTRIBUTES_TABLE);

final JcaGroupConfig group; {
group = (JcaGroupConfig) factory.newGroupConfig();
group.setId("attributes");
group.setLabel("Attributes");
group.setIsGridLayout(true);

group.addComponent(getAttribute(Pet.NAME, factory));
group.addComponent(getAttribute(Pet.KIND, factory));
group.addComponent(getAttribute(Pet.DATE_OF_BIRTH, factory));
group.addComponent(getAttribute(Pet.FIXED, factory));
}
panel.addComponent(group);
}
return panel;
}

JcaAttributeConfig getAttribute(final String id, final
ComponentConfigFactory factory) {
final JcaAttributeConfig attribute = (JcaAttributeConfig)
factory.newAttributeConfig();
attribute.setId(id);
return attribute;
}
}
4. Register the beans by updating Pet-configs.xml to include:
<bean class="com.acme.mvc.builders.PetInfoBuilder"/>
<bean class="com.acme.mvc.builders.PetInfoAttributesBuilder"/>
5. Add Pet-actionmodels.xml to site.xconf.
a. Just before the last line, </Configuration> add <AddToProperty name="com.ptc.netmarkets.util.misc.defaultActionmodels" value="config/actions/Petactionmodels.xml"/>.
b. Run bin/xconfmanager -pF to propagate the change.
6. Start/restart Windchill and verify (noting the Attachments tab for content).
Creating a UI