El cliente Teamcenter Rich Client (RAC), construido sobre la plataforma Eclipse RCP, permite una personalización profunda de la interfaz que supera ampliamente las capacidades del cliente web AWC. Muchas organizaciones lo prefieren precisamente por su flexibilidad para adaptar la experiencia del usuario a flujos de trabajo específicos.
Arquitectura base de RAC
RAC se apoya en el modelo modular de Eclipse, donde cada funcionalidad se encapsual en plugins que interactúan mediante puntos de extensión definidos. La estructura fundamental incluye:
- Workbench: Contenedor principal con perspectivas, vistas y editores
- Plugins: Unidades de despliegue con extensiones declarativas
- Puntos de extensión: Interfaces estandarizadas para inyectar funcionalidad
Configuración del entorno de desarrollo
- Instalar Eclipse IDE for RCP and RAP Developers
- Importar SDK de Teamcenter RAC como target platform
- Crear proyecto plugin con activador generado
- Agregar dependencias de Teamcenter en MANIFEST.MF
Personalización de menús
La integración de nuevos elementos en el menú principal se logra mediante el punto de extensión org.eclipse.ui.menus:
<extension point="org.eclipse.ui.menus">
<menuContribution locationURI="menu:com.teamcenter.rac.main.menu?after=additions">
<command commandId="empresa.extension.abrirUtilidad"
label="Herramientas personalizadas"
style="push"/>
</menuContribution>
</extension>
Para implementar la lógica asociada, se define un handler que hereda de AbstractHandler:
public class LanzadorUtilidad extends AbstractHandler {
@Override
public Object execute(ExecutionEvent evento) throws ExecutionException {
Shell ventana = HandlerUtil.getActiveShell(evento);
MessageBox dialogo = new MessageBox(ventana, SWT.ICON_INFORMATION | SWT.OK);
dialogo.setText("Acción personalizada");
dialogo.setMessage("Operación ejecutada desde extensión RAC");
dialogo.open();
return null;
}
}
Menús contextuales dinámicos
Los menús emergentes requieren identificar el tipo de objeto seleccionado. Este ejemplo agrega una opción al hacer clic derecho sobre ítems:
<extension point="org.eclipse.ui.popupMenus">
<objectContribution objectClass="com.teamcenter.rac.kernel.TCComponentItem"
id="empresa.contribucion.item">
<action id="empresa.accion.infoItem"
label="Mostrar metadatos extendidos"
class="empresa.acciones.InfoItemAction"
enablesFor="1"/>
</objectContribution>
</extension>
La clase de acción recupera los datos del componente seleccionado:
public class InfoItemAction implements IObjectActionDelegate {
private IStructuredSelection seleccion;
@Override
public void run(IAction action) {
if (seleccion.getFirstElement() instanceof TCComponentItem item) {
String codigo = item.getProperty("item_id");
System.out.println("Ítem seleccionado: " + codigo);
}
}
@Override
public void selectionChanged(IAction action, ISelection sel) {
this.seleccion = (IStructuredSelection) sel;
}
}
Barras de herramientas inteligentes
Los botones en la barra de herramientas pueden mostrar u ocultarse según el contexto actual:
<menuContribution locationURI="toolbar:com.teamcenter.rac.main.toolbar">
<command commandId="empresa.comando.procesarBOM"
icon="icons/bom.png"
tooltip="Procesar estructura BOM">
<visibleWhen>
<with variable="selection">
<iterate ifEmpty="false">
<instanceof value="com.teamcenter.rac.kernel.TCComponentBOMLine"/>
</iterate>
</with>
</visibleWhen>
</command>
</menuContribution>
Vistas personalizadas
Las vistas permiten mostrar información estructurada. Esta vista muestra una tabla con componentes:
public class VistaCatalogo extends ViewPart {
private Table tablaDatos;
@Override
public void createPartControl(Composite padre) {
tablaDatos = new Table(padre, SWT.BORDER | SWT.FULL_SELECTION);
configurarColumnas();
cargarContenido();
}
private void configurarColumnas() {
new TableColumn(tablaDatos, SWT.LEFT).setText("Referencia");
new TableColumn(tablaDatos, SWT.LEFT).setText("Descripción");
}
private void cargarContenido() {
TCSession sesion = obtenerSesionActual();
try {
TCComponent[] componentes = sesion.find("ItemRevision", "revision_list", "*");
for (TCComponent comp : componentes) {
new TableItem(tablaDatos, SWT.NONE).setText(new String[]{
comp.getProperty("item_id"),
comp.getProperty("object_desc")
});
}
} catch (TCException e) {
registrarError(e);
}
}
}
Diálogos modales
Los diálogos personalizados heredan de clases base como TitleAreaDialog:
public class DialogoParametros extends TitleAreaDialog {
private Text campoEntrada;
private String resultado;
@Override
protected Control createDialogArea(Composite contenedor) {
Composite area = (Composite) super.createDialogArea(contenedor);
GridLayout layout = new GridLayout(2, false);
area.setLayout(layout);
new Label(area, SWT.NONE).setText("Parámetro requerido:");
campoEntrada = new Text(area, SWT.BORDER);
campoEntrada.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
setTitle("Configuración avanzada");
setMessage("Especifique los valores necesarios");
return area;
}
@Override
protected void okPressed() {
resultado = campoEntrada.getText();
super.okPressed();
}
public String obtenerResultado() { return resultado; }
}
Páginas de propiedades
Las páginas de propiedades extienden la información mostrada en el panel de detalles:
<extension point="org.eclipse.ui.propertyPages">
<page name="Metadatos adicionales"
class="empresa.propiedades.PaginaItemExtendida"
objectClass="com.teamcenter.rac.kernel.TCComponentItem"/>
</extension>
Despliegue y pruebas
El método recomendado es copiar el JAR del plugin en el directorio dropins:
rac_client/
└── dropins/
└── empresa.extension.rac/
└── plugins/
└── empresa.extension.rac_1.0.0.jar
Para depuración, iniciar RAC con parámetros:
eclipsec.exe -consoleLog -debug -clean
Prácticas recomendadas
- Nomenclatura consistente: Usar dominio inverso para paquetes (com.empresa.rac.*)
- Carga perezosa: Inicializar recursos solo cuando sean necesarios
- Operaciones asíncronas: Evitar bloquear el hilo de UI
- Manejo de errores: Registrar excepciones y notificar al usuario
Ejemplo de operación en segundo plano:
new Thread(() -> {
ResultadoConsulta datos = consultarServidor();
Display.getDefault().asyncExec(() -> {
actualizarInterfaz(datos);
});
}).start();