/* ===============================================================================
*
* Part of the InfoGlue Content Management Platform (www.infoglue.org)
*
* ===============================================================================
*
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2, as published by the
* Free Software Foundation. See the file LICENSE.html for more information.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY, including 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 General Public License along with
* this program; if not, write to the Free Software Foundation, Inc. / 59 Temple
* Place, Suite 330 / Boston, MA 02111-1307 / USA.
*
* ===============================================================================
*/
package org.infoglue.deliver.applications.actions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.infoglue.cms.applications.common.VisualFormatter;
import org.infoglue.cms.applications.common.actions.InfoGlueAbstractAction;
import org.infoglue.cms.controllers.kernel.impl.simple.PublicationController;
import org.infoglue.cms.controllers.kernel.impl.simple.RepositoryController;
import org.infoglue.cms.controllers.kernel.impl.simple.ServerNodeController;
import org.infoglue.cms.entities.management.RepositoryVO;
import org.infoglue.cms.entities.publishing.PublicationDetailVO;
import org.infoglue.cms.entities.publishing.PublicationVO;
import org.infoglue.cms.entities.publishing.impl.simple.PublicationImpl;
import org.infoglue.cms.util.CmsPropertyHandler;
import org.infoglue.cms.util.DateHelper;
import org.infoglue.deliver.applications.databeans.CacheEvictionBean;
import org.infoglue.deliver.util.CacheController;
import org.infoglue.deliver.util.RequestAnalyser;
import org.infoglue.deliver.util.ThreadMonitor;
import com.google.gson.Gson;
/**
* This is the action that takes care of all incoming update-calls. This action is
* called by either the system or by replication-program and the class the distibutes the
* update-call to all the listeners which have registered earlier.
*
* @author Mattias Bogeblad
*/
public class UpdateCacheAction extends InfoGlueAbstractAction
{
private final static Logger logger = Logger.getLogger(UpdateCacheAction.class.getName());
private static VisualFormatter formatter = new VisualFormatter();
private ThreadMonitor tk = null;
private Integer publicationId = null;
public void setPublicationId(Integer publicationId)
{
this.publicationId = publicationId;
}
/**
* The constructor for this action - contains nothing right now.
*/
public UpdateCacheAction()
{
}
/**
* This method will allow for 3:rd party systems to send a publication message
* through to all deliver instances. This enables the same 3:rd party integrations to
* register pages where it's used with a special key which can later be cleared. It also enables
* those "publications" to be traced and logged in the same manner as all the others.
*/
public String doPassThroughPublication() throws Exception
{
String publisherName = getRequest().getParameter("publisherName");
if(publisherName == null || publisherName.equalsIgnoreCase(""))
publisherName = "SYSTEM";
String publicationName = getRequest().getParameter("publicationName");
if(publicationName == null || publicationName.equalsIgnoreCase(""))
publicationName = "3rd party pass through publication";
String publicationDescription = getRequest().getParameter("publicationDescription");
if(publicationDescription == null || publicationDescription.equalsIgnoreCase(""))
publicationDescription = "No description given.";
publicationDescription = publicationDescription + " Originating host: " + getRequest().getRemoteHost();
String repositoryId = getRequest().getParameter("repositoryId");
if(repositoryId == null || repositoryId.equalsIgnoreCase(""))
{
repositoryId = "" + RepositoryController.getController().getFirstRepositoryVO().getId();
}
else
{
if(repositoryId.equalsIgnoreCase("InfoglueCalendar"))
{
for(RepositoryVO repoVO : (List<RepositoryVO>)RepositoryController.getController().getRepositoryVOList())
{
if(repoVO.getName().toLowerCase().indexOf("calendar") > -1)
{
repositoryId = "" + repoVO.getId();
break;
}
}
}
else
{
try
{
repositoryId = "" + RepositoryController.getController().getRepositoryVOWithId(Integer.parseInt(repositoryId)).getId();
}
catch (Exception e) {
logger.error("Wrong repository was sent from 3:rd party client to pass through publication:" + repositoryId + ". Defaulting to first repo.");
repositoryId = "" + RepositoryController.getController().getFirstRepositoryVO().getId();
}
}
}
String className = getRequest().getParameter("className");
String objectId = getRequest().getParameter("objectId");
String objectName = getRequest().getParameter("objectName");
String objectDescription = getRequest().getParameter("objectDescription");
if(objectDescription == null || objectDescription.equalsIgnoreCase(""))
objectDescription = "No description given.";
PublicationDetailVO publicationDetailVO = new PublicationDetailVO();
publicationDetailVO.setCreationDateTime(DateHelper.getSecondPreciseDate());
publicationDetailVO.setDescription(objectDescription);
publicationDetailVO.setEntityClass(className);
publicationDetailVO.setEntityId(new Integer(objectId));
publicationDetailVO.setName("" + objectName);
publicationDetailVO.setTypeId(PublicationDetailVO.PUBLISH);
publicationDetailVO.setCreator(publisherName);
List<PublicationDetailVO> publicationDetailVOList = new ArrayList<PublicationDetailVO>();
publicationDetailVOList.add(publicationDetailVO);
PublicationVO publicationVO = new PublicationVO();
publicationVO.setName(publicationName);
publicationVO.setDescription(publicationDescription);
publicationVO.setRepositoryId(new Integer(repositoryId));
publicationVO = PublicationController.getController().createAndPublish(publicationVO, publicationDetailVOList, publisherName);
/*
NotificationMessage notificationMessage = new NotificationMessage("doClearPageCacheOnAllNodes:", className, "SYSTEM", NotificationMessage.PUBLISHING, objectId, ""+objectName);
RemoteCacheUpdater.getSystemNotificationMessages().add(notificationMessage);
RemoteCacheUpdater.pushAndClearSystemNotificationMessages("SYSTEM");
*/
this.getResponse().getWriter().println("cache clear instruction ok");
return NONE;
}
/**
* This method will just reply to a testcall.
*/
public String doTest() throws Exception
{
String operatingMode = CmsPropertyHandler.getOperatingMode();
if(operatingMode != null && operatingMode.equalsIgnoreCase("3"))
{
if(!ServerNodeController.getController().getIsIPAllowed(this.getRequest()))
{
logger.warn("A user from an IP(" + this.getRequest().getRemoteAddr() + ") which is not allowed tried to call UpdateCache!test.");
this.getResponse().setContentType("text/plain");
this.getResponse().setStatus(HttpServletResponse.SC_FORBIDDEN);
this.getResponse().getWriter().println("You have no access to this view - talk to your administrator if you should.");
return NONE;
}
}
this.getResponse().setContentType("text/plain");
this.getResponse().getWriter().println("test ok - cache action available");
return NONE;
}
/**
* This method return status information about a certain publication.
* It should be able to inform us about if the publication was performed or if it's waiting or ongoing.
*/
public String doGetPublicationState() throws Exception
{
String operatingMode = CmsPropertyHandler.getOperatingMode();
if(operatingMode != null && operatingMode.equalsIgnoreCase("3"))
{
if(!ServerNodeController.getController().getIsIPAllowed(this.getRequest()))
{
logger.warn("A user from an IP(" + this.getRequest().getRemoteAddr() + ") which is not allowed tried to call UpdateCache!getPublicationState.");
this.getResponse().setContentType("text/plain");
this.getResponse().setStatus(HttpServletResponse.SC_FORBIDDEN);
this.getResponse().getWriter().println("You have no access to this view - talk to your administrator if you should.");
return NONE;
}
}
StringBuffer sb = new StringBuffer();
List<CacheEvictionBean> latestPublications = RequestAnalyser.getRequestAnalyser().getLatestPublications();
List<CacheEvictionBean> ongoingPublications = RequestAnalyser.getRequestAnalyser().getOngoingPublications();
CacheEvictionBean foundPublishedBean = null;
CacheEvictionBean foundOngoingPublicationBean = null;
for(CacheEvictionBean latestPublication : latestPublications)
{
if(latestPublication.getPublicationId().equals(this.publicationId))
foundPublishedBean = latestPublication;
}
for(CacheEvictionBean ongoingPublication : ongoingPublications)
{
foundOngoingPublicationBean = ongoingPublication;
}
if(foundPublishedBean != null)
sb.append("" + foundPublishedBean.toQueryString());
else if(foundOngoingPublicationBean != null)
sb.append("" + foundOngoingPublicationBean.toQueryString());
else
sb.append("status=Unknown; serverStartDateTime:" + formatter.formatDate(CmsPropertyHandler.getStartupTime(), "yyyy-MM-dd HH:mm:ss"));
this.getResponse().setContentType("text/plain");
this.getResponse().getWriter().println("" + sb.toString());
return NONE;
}
/**
* This method return status information about a certain publication. It should be able to inform us about if the publication was performed or if it's waiting or ongoing.
*/
public String doGetOngoingPublications() throws Exception
{
String operatingMode = CmsPropertyHandler.getOperatingMode();
if(operatingMode != null && operatingMode.equalsIgnoreCase("3"))
{
if(!ServerNodeController.getController().getIsIPAllowed(this.getRequest()))
{
logger.warn("A user from an IP(" + this.getRequest().getRemoteAddr() + ") which is not allowed tried to call UpdateCache!getOngoingPublications.");
this.getResponse().setContentType("text/plain");
this.getResponse().setStatus(HttpServletResponse.SC_FORBIDDEN);
this.getResponse().getWriter().println("You have no access to this view - talk to your administrator if you should.");
return NONE;
}
}
List<CacheEvictionBean> ongoingPublications = RequestAnalyser.getRequestAnalyser().getOngoingPublications();
Gson gson = new Gson();
String json = gson.toJson(ongoingPublications);
this.getResponse().setContentType("text/plain");
this.getResponse().getWriter().println(json);
return NONE;
}
/**
* This method return status information about a certain publication. It should be able to inform us about if the publication was performed or if it's waiting or ongoing.
*/
public String doGetLatestPublications() throws Exception
{
String operatingMode = CmsPropertyHandler.getOperatingMode();
if(operatingMode != null && operatingMode.equalsIgnoreCase("3"))
{
if(!ServerNodeController.getController().getIsIPAllowed(this.getRequest()))
{
logger.warn("A user from an IP(" + this.getRequest().getRemoteAddr() + ") which is not allowed tried to call UpdateCache!getLatestPublications.");
this.getResponse().setContentType("text/plain");
this.getResponse().setStatus(HttpServletResponse.SC_FORBIDDEN);
this.getResponse().getWriter().println("You have no access to this view - talk to your administrator if you should.");
return NONE;
}
}
List<CacheEvictionBean> latestPublications = RequestAnalyser.getRequestAnalyser().getLatestPublications();
Gson gson = new Gson();
String json = gson.toJson(latestPublications);
this.getResponse().setContentType("text/plain");
this.getResponse().getWriter().println(json);
return NONE;
}
/**
* This method return debug information about a certain content or page from each live server.
*/
public String doEntityCacheDebugInformation() throws Exception
{
String operatingMode = CmsPropertyHandler.getOperatingMode();
if(operatingMode != null && operatingMode.equalsIgnoreCase("3"))
{
if(!ServerNodeController.getController().getIsIPAllowed(this.getRequest()))
{
logger.warn("A user from an IP(" + this.getRequest().getRemoteAddr() + ") which is not allowed tried to call UpdateCache!getPublicationState.");
this.getResponse().setContentType("text/plain");
this.getResponse().setStatus(HttpServletResponse.SC_FORBIDDEN);
this.getResponse().getWriter().println("You have no access to this view - talk to your administrator if you should.");
return NONE;
}
}
StringBuffer sb = new StringBuffer();
String cacheDebugInfo = CacheController.debugCache(getRequest().getParameter("entityName"), getRequest().getParameter("entityId"), (String)CmsPropertyHandler.getCacheSettings().get("cacheNamesToSkipInDebug"), getRequest().getParameter("forceClear"));
logger.info("cacheDebugInfo:" + cacheDebugInfo);
sb.append(cacheDebugInfo);
this.getResponse().setContentType("text/plain");
this.getResponse().getWriter().println("" + sb.toString());
return NONE;
}
/**
* This method will just reply to a testcall.
*/
public String doTestV3() throws Exception
{
String operatingMode = CmsPropertyHandler.getOperatingMode();
if(operatingMode != null && operatingMode.equalsIgnoreCase("3"))
{
if(!ServerNodeController.getController().getIsIPAllowed(this.getRequest()))
{
logger.warn("A user from an IP(" + this.getRequest().getRemoteAddr() + ") which is not allowed tried to call UpdateCache!testV3.");
this.getResponse().setContentType("text/plain");
this.getResponse().setStatus(HttpServletResponse.SC_FORBIDDEN);
this.getResponse().getWriter().println("You have no access to this view - talk to your administrator if you should.");
return NONE;
}
}
this.getResponse().setContentType("text/html");
this.getResponse().getWriter().println("<html><body>test ok - cache action available</body></html>");
return NONE;
}
/**
* This method is the application entry-point. The parameters has been set through the setters
* and now we just have to render the appropriate output.
*/
public String doExecute() throws Exception
{
/*
System.out.println("PATH: " + getCurrentURL());
if(getCurrentURL().contains("infoglueDeliverLive2"))
return NONE;
*/
logger.info("A cache update was received");
if(!CmsPropertyHandler.getOperatingMode().equals("3"))
tk = new ThreadMonitor(2000, this.getRequest(), "Update cache took to long", false);
logger.info("Update Cache starts..");
String operatingMode = CmsPropertyHandler.getOperatingMode();
if(operatingMode != null && operatingMode.equalsIgnoreCase("3"))
{
long start = System.currentTimeMillis();
if(!ServerNodeController.getController().getIsIPAllowed(this.getRequest()))
{
logger.warn("A user from an IP(" + this.getRequest().getRemoteAddr() + ") which is not allowed tried to call UpdateCache.action.");
this.getResponse().setContentType("text/plain");
this.getResponse().setStatus(HttpServletResponse.SC_FORBIDDEN);
this.getResponse().getWriter().println("You have no access to this view - talk to your administrator if you should.");
return NONE;
}
}
try
{
//Iterate through all registered listeners and call them... dont place logic here... have specialized handlers.
//logger.info("className:" + className);
//logger.info("objectId:" + objectId);
List newNotificationList = new ArrayList();
int i = 0;
String userName = this.getRequest().getParameter(i + ".userName");
String timestamp = this.getRequest().getParameter(i + ".timestamp");
String className = this.getRequest().getParameter(i + ".className");
String typeId = this.getRequest().getParameter(i + ".typeId");
String objectId = this.getRequest().getParameter(i + ".objectId");
String objectName = this.getRequest().getParameter(i + ".objectName");
//A very special parameter only used in working environments. Notifies what has changes more precisly
Map<String,String> extraInfo = new HashMap<String,String>();
String changedAttributeNames = this.getRequest().getParameter(i + ".changedAttributeNames");
String contentId = this.getRequest().getParameter(i + ".contentId");
String parentContentId = this.getRequest().getParameter(i + ".parentContentId");
String contentTypeDefinitionId = this.getRequest().getParameter(i + ".contentTypeDefinitionId");
String contentIsProtected = this.getRequest().getParameter(i + ".contentIsProtected");
String siteNodeId = this.getRequest().getParameter(i + ".siteNodeId");
String parentSiteNodeId = this.getRequest().getParameter(i + ".parentSiteNodeId");
String repositoryId = this.getRequest().getParameter(i + ".repositoryId");
//System.out.println("contentId:" + contentId);
//System.out.println("parentContentId:" + parentContentId);
//System.out.println("siteNodeId:" + siteNodeId);
//System.out.println("parentSiteNodeId:" + parentSiteNodeId);
//System.out.println("repositoryId:" + repositoryId);
if(changedAttributeNames != null)
extraInfo.put("changedAttributeNames", changedAttributeNames);
if(contentId != null)
extraInfo.put("contentId", contentId);
if(parentContentId != null)
extraInfo.put("parentContentId", parentContentId);
if(contentTypeDefinitionId != null)
extraInfo.put("contentTypeDefinitionId", contentTypeDefinitionId);
if(contentIsProtected != null)
extraInfo.put("contentIsProtected", contentIsProtected);
if(siteNodeId != null)
extraInfo.put("siteNodeId", siteNodeId);
if(parentSiteNodeId != null)
extraInfo.put("parentSiteNodeId", parentSiteNodeId);
if(repositoryId != null)
extraInfo.put("repositoryId", repositoryId);
while(className != null && !className.equals(""))
{
logger.info("Cache update info:" + className + "/" + objectId);
Integer publicationId = -1;
if(className.indexOf(PublicationImpl.class.getName()) > -1)
publicationId = Integer.parseInt(objectId);
boolean skip = false;
if(timestamp != null && !timestamp.equals(""))
{
try
{
long ts = Long.parseLong(timestamp);
if(ts < CmsPropertyHandler.getStartupTime().getTime())
skip = true;
}
catch (Exception e)
{
logger.error("Could not read timestamp:" + timestamp);
}
}
if(!skip)
{
CacheEvictionBean cacheEvictionBean = new CacheEvictionBean(publicationId, userName, timestamp, className, typeId, objectId, objectName, extraInfo);
newNotificationList.add(cacheEvictionBean);
/*
synchronized(CacheController.notifications)
{
CacheController.notifications.add(cacheEvictionBean);
}
*/
logger.info("Added a cacheEvictionBean " + cacheEvictionBean.getClassName() + ":" + cacheEvictionBean.getTypeId() + ":" + cacheEvictionBean.getObjectName() + ":" + cacheEvictionBean.getObjectId());
}
else
logger.warn("Skipped a cacheEvictionBean as it's timestamp was earlier than the server start");
i++;
userName = this.getRequest().getParameter(i + ".userName");
timestamp = this.getRequest().getParameter(i + ".timestamp");
className = this.getRequest().getParameter(i + ".className");
typeId = this.getRequest().getParameter(i + ".typeId");
objectId = this.getRequest().getParameter(i + ".objectId");
objectName = this.getRequest().getParameter(i + ".objectName");
//A very special parameter only used in working environments. Notifies what has changes more precisly
extraInfo = new HashMap<String,String>();
changedAttributeNames = this.getRequest().getParameter(i + ".changedAttributeNames");
contentId = this.getRequest().getParameter(i + ".contentId");
parentContentId = this.getRequest().getParameter(i + ".parentContentId");
contentTypeDefinitionId = this.getRequest().getParameter(i + ".contentTypeDefinitionId");
contentIsProtected = this.getRequest().getParameter(i + ".contentIsProtected");
siteNodeId = this.getRequest().getParameter(i + ".siteNodeId");
parentSiteNodeId = this.getRequest().getParameter(i + ".parentSiteNodeId");
repositoryId = this.getRequest().getParameter(i + ".repositoryId");
// System.out.println("contentId:" + contentId);
// System.out.println("parentContentId:" + parentContentId);
// System.out.println("siteNodeId:" + siteNodeId);
// System.out.println("parentSiteNodeId:" + parentSiteNodeId);
// System.out.println("repositoryId:" + repositoryId);
if(changedAttributeNames != null)
extraInfo.put("changedAttributeNames", changedAttributeNames);
if(contentId != null)
extraInfo.put("contentId", contentId);
if(parentContentId != null)
extraInfo.put("parentContentId", parentContentId);
if(contentTypeDefinitionId != null)
extraInfo.put("contentTypeDefinitionId", contentTypeDefinitionId);
if(contentIsProtected != null)
extraInfo.put("contentIsProtected", contentIsProtected);
if(siteNodeId != null)
extraInfo.put("siteNodeId", siteNodeId);
if(parentSiteNodeId != null)
extraInfo.put("parentSiteNodeId", parentSiteNodeId);
if(repositoryId != null)
extraInfo.put("repositoryId", repositoryId);
}
if(i == 0)
{
userName = this.getRequest().getParameter("userName");
timestamp = this.getRequest().getParameter("timestamp");
className = this.getRequest().getParameter("className");
typeId = this.getRequest().getParameter("typeId");
objectId = this.getRequest().getParameter("objectId");
objectName = this.getRequest().getParameter("objectName");
//A very special parameter only used in working environments. Notifies what has changes more precisly
extraInfo = new HashMap<String,String>();
changedAttributeNames = this.getRequest().getParameter("changedAttributeNames");
contentId = this.getRequest().getParameter("contentId");
parentContentId = this.getRequest().getParameter("parentContentId");
contentTypeDefinitionId = this.getRequest().getParameter("contentTypeDefinitionId");
contentIsProtected = this.getRequest().getParameter("contentIsProtected");
siteNodeId = this.getRequest().getParameter("siteNodeId");
parentSiteNodeId = this.getRequest().getParameter("parentSiteNodeId");
repositoryId = this.getRequest().getParameter("repositoryId");
// System.out.println("contentId:" + contentId);
// System.out.println("parentContentId:" + parentContentId);
// System.out.println("siteNodeId:" + siteNodeId);
// System.out.println("parentSiteNodeId:" + parentSiteNodeId);
// System.out.println("repositoryId:" + repositoryId);
if(changedAttributeNames != null)
extraInfo.put("changedAttributeNames", changedAttributeNames);
if(contentId != null)
extraInfo.put("contentId", contentId);
if(parentContentId != null)
extraInfo.put("parentContentId", parentContentId);
if(contentTypeDefinitionId != null)
extraInfo.put("contentTypeDefinitionId", contentTypeDefinitionId);
if(contentIsProtected != null)
extraInfo.put("contentIsProtected", contentIsProtected);
if(siteNodeId != null)
extraInfo.put("siteNodeId", siteNodeId);
if(parentSiteNodeId != null)
extraInfo.put("parentSiteNodeId", parentSiteNodeId);
if(repositoryId != null)
extraInfo.put("repositoryId", repositoryId);
Integer publicationId = -1;
if(className.indexOf(PublicationImpl.class.getName()) > -1)
publicationId = Integer.parseInt(objectId);
boolean skip = false;
if(timestamp != null && !timestamp.equals(""))
{
try
{
long ts = Long.parseLong(timestamp);
if(ts < CmsPropertyHandler.getStartupTime().getTime())
skip = true;
}
catch (Exception e)
{
logger.error("Could not read timestamp:" + timestamp);
}
}
if(!skip)
{
CacheEvictionBean cacheEvictionBean = new CacheEvictionBean(publicationId, userName, timestamp, className, typeId, objectId, objectName, extraInfo);
newNotificationList.add(cacheEvictionBean);
/*
synchronized(CacheController.notifications)
{
CacheController.notifications.add(cacheEvictionBean);
}
logger.warn("Added an oldSchool cacheEvictionBean " + cacheEvictionBean.getClassName() + ":" + cacheEvictionBean.getTypeId() + ":" + cacheEvictionBean.getObjectName() + ":" + cacheEvictionBean.getObjectId());
*/
logger.info("Added a cacheEvictionBean " + cacheEvictionBean.getClassName() + ":" + cacheEvictionBean.getTypeId() + ":" + cacheEvictionBean.getObjectName() + ":" + cacheEvictionBean.getObjectId());
}
else
logger.warn("Skipped a cacheEvictionBean as it's timestamp was earlier than the server start");
}
/*
//TODO - place check here maybe??
synchronized(RequestAnalyser.getRequestAnalyser())
{
if(RequestAnalyser.getRequestAnalyser().getBlockRequests())
{
logger.warn("evictWaitingCache allready in progress - returning to avoid conflict");
return;
}
RequestAnalyser.getRequestAnalyser().setBlockRequests(true);
}
*/
//synchronized(this)
//{
synchronized(CacheController.notifications)
{
CacheController.notifications.addAll(newNotificationList);
}
//}
//new Thread(new Runnable() { public void run() {try {Thread.sleep(100); CacheController.evictWaitingCache(false);} catch (Exception e) {}}}).start();
logger.info("UpdateCache finished...");
}
catch(Exception e)
{
logger.error("Error in UpdateCache: " + e.getMessage(), e);
}
catch(Throwable t)
{
logger.error("Error in UpdateCache: " + t.getMessage());
}
//this.getHttpSession().invalidate();
logger.info("Update Cache stops..");
if(tk != null)
tk.done();
return NONE;
}
/**
* Setters and getters for all things sent to the page in the request
*/
/*
public void setClassName(String className)
{
this.className = className;
}
public void setObjectId(String objectId)
{
this.objectId = objectId;
}
public void setObjectName(String objectName)
{
this.objectName = objectName;
}
public void setTypeId(String typeId)
{
this.typeId = typeId;
}
*/
}