Skip to main content
10-Marble
August 26, 2025
Solved

Throw Warning Message in Custom Listener

  • August 26, 2025
  • 1 reply
  • 891 views

Version: Windchill 13.0


Description:

We have customized a PRE_WORKSPACE_CHECKIN listener to process an attachment file and populate attributes on the associated CAD document during the check-in process. It works great, but sometimes users forget to add the attachment, which results in none of the necessary attributes being populated. Is there a way to throw a warning (or error that can then be bypassed) to the user during check-in to tell them they are missing the attachment? Ideally I would like to call this in the custom listener.

 

public void notifyVetoableEvent(Object event) throws Exception{
	if(!(event instanceof KeyedEvent)) {
		return;
	}
	//Object target = ((KeyedEvent) event).getEventTarget();
	Object type = ((KeyedEvent) event).getEventType();
	if(type.equals(EPMWorkspaceManagerEvent.PRE_WORKSPACE_CHECKIN))
	{
		EPMWorkspaceManagerEvent wsEvent = (EPMWorkspaceManagerEvent) event;
		WTSet workingCopies = ((WTKeyedMap) ((EPMWorkspaceManagerEvent) event).getWIPMap()).wtKeySet();
		WTCollection epmDocs = workingCopies.subCollection(EPMDocument.class);
		Iterator docItr = epmDocs.persistableIterator(EPMDocument.class, true);
		while (docItr.hasNext()) {
			EPMDocument epmDoc = (EPMDocument) docItr.next();
			wt.fc.Persistable pers = (wt.fc.Persistable) epmDoc;
			com.ptc.core.meta.common.TypeIdentifier tiObj = wt.type.ClientTypedUtility.getTypeIdentifier(pers);
			String objType = tiObj.toString();
			if( objType.endsWith("VOCCADDocument")) {
				QCheckHelper qChecker = new QCheckHelper(epmDoc);
				
				// WARNING THROW SHOULD HAPPEN HERE, PSUEDO CODE INCLUDED FOR REFERENCE 
				if (qChecker.hasQCFile() == false) {
					new FeedBackMessage("Missing QC File! Continue check-in without adding?");
					// IF USER CLICKS "PROCEED" BELOW CODE EXECUTES AND POPULATES WITH BLANK VALUES
					// IF USER CLICKS "CANCEL" THE CHECK-IN IS ABORTED
				}
				// END OF PSUEDO CODE, REMAINING CODE WORKS AS EXPECTED
				
				Map<String, String> attr_value_map = new HashMap<String, String>(7);
				attr_value_map.put("QC_ACTACTION", qChecker.getActAction());
				attr_value_map.put("QC_ASSESSMENT", qChecker.getAssessment());
				attr_value_map.put("QC_CHECK_DATE", qChecker.getCheckDate());
				attr_value_map.put("QC_CHECK_TIME", qChecker.getCheckTime());
				attr_value_map.put("QC_CHECK_USER", qChecker.getCheckUser());
				attr_value_map.put("QC_PROFILE_NAME", qChecker.getProfileName());

				WTKeyedMap keyed_map = new WTKeyedHashMap(1);
				keyed_map.put(epmDoc, attr_value_map);

				EPMWorkspaceHelper.manager.setAttributes(wsEvent.getWorkspace() , keyed_map);
			}
		}
	}
}

 

Best answer by HelesicPetr

Hi @marshall_brock 

As I wrote, it it more complicated. 

here is an example how to create message with options for the error message

ArrayList<String> incorrectMessages = new ArrayList<>();
incorrectMessages.add("Delete WTP case ProcessPlan error!");

WTPDeleteMessage errorTitle = new WTPDeleteMessage("!!!! WARNING !!!!: ", "35", new Object[]{incorrectMessages});

ConflictType cType = WTPDeleteConflictType.DELETE_WTP_NOT_ALLOWED;
ResolutionType rType = ResolutionType.RETRY;
ResolutionType sType = ResolutionType.SKIP;
ConflictElement conflictElement = new ConflictElement(cType, new ResolutionType[]{sType, rType}, sType, errorTitle, wtp);
ConflictException conflict = new ConflictException(new ConflictElement[]{conflictElement});

ResolutionType resolutionList = ConflictServerHelper.getResolution(wtp, cType); // VERY IMPORTANT API TO GET RESOLUTION OPTIONS

if (resolutionList == null)
{
	throw conflict;
} else
{
	String option = resolutionList.getDisplay(Locale.US);

	if (option.equals("Retry"))
	{
		logger.info(String.format("WTPart linked to Process Plan is deleted. WTPart: %s, Process Plan: %s User %s", wtp.getNumber(), plan.getNumber(), user.getName()));
	} else
	{
		throw conflict;
	}
}

 

API to override conflict on EPMWorkspaceHelper.manager.checkout

You have to create own conflict type 

In my example I used own class WTPDeleteConflictType

How to create RbInfo file

How to create a drop down list in a workflow instance task detail page of Windchill PDMLink

 

Also I created own WTPDeleteMessage based on WTMessage.class

 

Hope this can help you.

 

PetrH

1 reply

avillanueva
23-Emerald I
23-Emerald I
August 27, 2025

Related to your other linked message, I did this on a rename listener by throwing a WTException

throw new WTException("Rename for Part " + master.getNumber() + " rejected since name length exceeds 40 characters for SAP");

though WTException is a hard no bypass way which might not work in your situation. 

 

10-Marble
August 28, 2025

Thanks for the response, but you are correct that this would produce a hard error with no bypass which is undesirable in my situation. This is what I plan to use as a last resort. I was hoping to find a solution using either the conflict manager (ConflictElement/Resolution API) or FeedbackMessage, but I'm not very familiar with either.

HelesicPetr
22-Sapphire II
22-Sapphire II
August 28, 2025

Hi @marshall_brock 

As I wrote, it it more complicated. 

here is an example how to create message with options for the error message

ArrayList<String> incorrectMessages = new ArrayList<>();
incorrectMessages.add("Delete WTP case ProcessPlan error!");

WTPDeleteMessage errorTitle = new WTPDeleteMessage("!!!! WARNING !!!!: ", "35", new Object[]{incorrectMessages});

ConflictType cType = WTPDeleteConflictType.DELETE_WTP_NOT_ALLOWED;
ResolutionType rType = ResolutionType.RETRY;
ResolutionType sType = ResolutionType.SKIP;
ConflictElement conflictElement = new ConflictElement(cType, new ResolutionType[]{sType, rType}, sType, errorTitle, wtp);
ConflictException conflict = new ConflictException(new ConflictElement[]{conflictElement});

ResolutionType resolutionList = ConflictServerHelper.getResolution(wtp, cType); // VERY IMPORTANT API TO GET RESOLUTION OPTIONS

if (resolutionList == null)
{
	throw conflict;
} else
{
	String option = resolutionList.getDisplay(Locale.US);

	if (option.equals("Retry"))
	{
		logger.info(String.format("WTPart linked to Process Plan is deleted. WTPart: %s, Process Plan: %s User %s", wtp.getNumber(), plan.getNumber(), user.getName()));
	} else
	{
		throw conflict;
	}
}

 

API to override conflict on EPMWorkspaceHelper.manager.checkout

You have to create own conflict type 

In my example I used own class WTPDeleteConflictType

How to create RbInfo file

How to create a drop down list in a workflow instance task detail page of Windchill PDMLink

 

Also I created own WTPDeleteMessage based on WTMessage.class

 

Hope this can help you.

 

PetrH

PetrH