/* * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package com.arsdigita.portalserver; import com.arsdigita.domain.DomainObjectFactory; import com.arsdigita.kernel.Group; import com.arsdigita.kernel.Party; import com.arsdigita.kernel.PartyCollection; import com.arsdigita.kernel.Resource; import com.arsdigita.kernel.User; import com.arsdigita.kernel.permissions.PermissionDescriptor; import com.arsdigita.kernel.permissions.PermissionService; import com.arsdigita.kernel.permissions.PrivilegeDescriptor; import com.arsdigita.persistence.DataAssociation; import com.arsdigita.persistence.DataAssociationCursor; import com.arsdigita.persistence.DataCollection; import com.arsdigita.persistence.DataObject; import com.arsdigita.persistence.DataQuery; import com.arsdigita.persistence.DataQueryDataCollectionAdapter; import com.arsdigita.persistence.OID; import com.arsdigita.persistence.SessionManager; import com.arsdigita.persistence.Filter; import com.arsdigita.portal.apportlet.AppPortlet; import com.arsdigita.portal.Portlet; import com.arsdigita.portal.AgentPortlet; import com.arsdigita.portal.PortletCollection; import com.arsdigita.util.Assert; import com.arsdigita.web.Application; import com.arsdigita.web.ApplicationCollection; import com.arsdigita.web.ApplicationType; import java.math.BigDecimal; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.Iterator; import java.util.LinkedList; import javax.servlet.http.HttpServletRequest; import org.apache.log4j.Category; /** *
A PortalSite is a mountable Portal instance, complete
* with URL. A PortalSite is made up of one or more PortalTabs.
* A PortalTab is in turn comprised of zero or more Portlets.
A PortalSite presents what the User considers to be
* a "Portal". For the sake of clarity, however, in the source code side
* of things, a Portal is actually a domain class in CCM Core,
* used as a foundation class by PortalSite.
createPortalSite() method for a new PortalSite object.
*/
protected PortalSite(DataObject dataObject) {
super(dataObject);
}
@Override
protected void initialize() {
super.initialize();
if (isNew()) {
setReady(false);
setDraft(false);
setPersonalizable(false);
setUnarchived();
setCreationDate();
}
}
public static PortalSite createPortalSite
(String urlName, String title, PortalSite parent,
boolean inheritPermissions) {
ApplicationType type =
ApplicationType.retrieveApplicationTypeForApplication
(BASE_DATA_OBJECT_TYPE);
PortalSite ps = (PortalSite) Application.createApplication
(type, urlName, title, parent);
ps.setUnarchived();
ps.setDraft(false);
ps.setCreationDate();
ps.setPersonalizable(false);
if (!inheritPermissions) {
PermissionService.setContext(ps, null);
}
return ps;
}
/**
* Creates an Instance ot ApplicationType PortalSite as a legacy free
* application.
* @param urlName
* @param title
* @param parent
* @return
*/
public static PortalSite createPortalSite(String urlName,
String title,
PortalSite parent) {
ApplicationType type =
ApplicationType.retrieveApplicationTypeForApplication
(BASE_DATA_OBJECT_TYPE);
PortalSite ps = (PortalSite) Application.createApplication
(type, urlName, title, parent);
ps.setUnarchived();
ps.setDraft(false);
ps.setCreationDate();
ps.setPersonalizable(false);
return ps;
}
/**
* @deprecated Use PortalSite.retrieveAllPortalSites().
*/
public static PortalSiteCollection retrieveAll() {
return PortalSite.retrieveAllPortalSites();
}
/**
* Returns a collection of all PortalSite's currently mounted on
* the server. Cannot return null. The collection returned includes
* archived portals as well. Most applications will want to call
* retrieveAllActivePortalSites()
*/
public static PortalSiteCollection retrieveAllPortalSites() {
DataCollection dataCollection =
SessionManager.getSession().retrieve(BASE_DATA_OBJECT_TYPE);
PortalSiteCollection portalsiteCollection = new PortalSiteCollection
(dataCollection);
return portalsiteCollection;
}
/**
* Returns a collection of all active PortalSite's currently mounted on
* the server. Cannot return null. The collection returned does not include
* archived portals.
*/
public static PortalSiteCollection retrieveAllActivePortalSites() {
DataCollection dataCollection =
SessionManager.getSession().retrieve(BASE_DATA_OBJECT_TYPE);
PortalSiteCollection portalsiteCollection = new PortalSiteCollection
(dataCollection);
portalsiteCollection.filterForArchived();
return portalsiteCollection;
}
/**
*
* @param siteNode
* @return Can return null.
*/
/* OBVIOUSLY NO LONGER USED
public static PortalSite retrievePortalSiteForSiteNode(SiteNode siteNode) {
DataQuery query = SessionManager.getSession().retrieveQuery
("com.arsdigita.workspace.workspaceForSiteNodeID");
query.setParameter("siteNodeID", siteNode.getID());
PortalSite portalsite = null;
if (query.next()) {
DataObject dataObject = (DataObject) query.get("workspace");
portalsite = PortalSite.retrievePortalSite(dataObject);
}
query.close();
return portalsite;
}
*/
// Can return null.
public static PortalSite retrievePortalSite(BigDecimal id) {
return (PortalSite) Application.retrieveApplication(id);
}
// Can return null.
public static PortalSite retrievePortalSite(OID oid) {
return (PortalSite) Application.retrieveApplication(oid);
}
// Can return null.
public static PortalSite retrievePortalSite(DataObject dataObject) {
return (PortalSite) Application.retrieveApplication(dataObject);
}
@Override
protected void beforeSave() {
m_wasNew = isNew();
super.beforeSave();
}
@Override
protected void afterSave() {
super.afterSave();
if (m_wasNew) {
Role role = Role.createRole
(this, "Members", "Member", "", true, Role.MEMBER_TYPE);
setMemberRole(role);
role.save();
PermissionService.grantPermission
(new PermissionDescriptor
(PrivilegeDescriptor.READ, this, getMemberRole()));
PortalSite parent = getPortalSiteForApplication(this);
if (parent != null) {
parent.addMember(getMemberRole());
parent.save();
}
m_wasNew = false;
}
}
//protected void beforeDelete() {
@Override
public void beforeDelete() {
//First, make certain that portalsite to be deleted has no children
PortalSiteCollection psc = getAllChildPortalSites();
if(!psc.isEmpty())
throw new UnsupportedOperationException
("Deletion of PortalSites does not support recursion: you" +
"must delete children of this portal site first.");
}
//
// Association properties
//
public ApplicationCollection getFullPagePortalSiteApplications() {
ApplicationCollection applications = getChildApplications();
applications.filterToPortalSiteApplications();
applications.filterToHasFullPageView();
return applications;
}
/**
* This method is used by portlet create and app create form flow
* to determine if an apptype is already present for a PortalSite.
*/
public boolean isAppTypeInPortalSite(ApplicationType appType) {
ApplicationCollection apps = getFullPagePortalSiteApplications();
ApplicationType atp;
while (apps.next()) {
atp = apps.getApplication().getApplicationType();
if (atp.getID().equals(appType.getID())) {
apps.close();
return true;
}
}
apps.close();
return false;
}
public PortalSiteCollection getChildPortalSites() {
DataQuery query = SessionManager.getSession().retrieveQuery
("com.arsdigita.workspace.childWorkspacesForApplicationID");
query.setParameter("applicationID", getID());
DataCollection collection =
new DataQueryDataCollectionAdapter(query, "workspace");
query.close();
PortalSiteCollection psc = new PortalSiteCollection(collection);
psc.filterForUnarchived();
return psc;
}
public PortalSiteCollection getAllChildPortalSites() {
DataQuery query = SessionManager.getSession().retrieveQuery
("com.arsdigita.workspace.childWorkspacesForApplicationID");
query.setParameter("applicationID", getID());
DataCollection collection =
new DataQueryDataCollectionAdapter(query, "workspace");
query.close();
return new PortalSiteCollection(collection);
}
public PortalSiteCollection getRelatedPortalSites() {
DataAssociation association = (DataAssociation) get("relatedWorkspace");
PortalSiteCollection psc =
new PortalSiteCollection(association.cursor());
psc.filterForUnarchived();
return psc;
}
public PortalSiteCollection getAllRelatedPortalSites() {
DataAssociation association = (DataAssociation) get("relatedWorkspace");
PortalSiteCollection psc =
new PortalSiteCollection(association.cursor());
return psc;
}
public static PortalSite getPortalSiteForApplication(Application app) {
Application application = app.getParentApplication();
if (application == null) {
return null;
}
// Sometimes a Portalsite has an ordinary application as its
// parent. This is true, for instance, of personal
// portals. In these cases we return null, because there
// is no parent *Portal*.
if (!(application instanceof PortalSite)) {
return null;
}
return (PortalSite) application;
}
public static PortalSite getPortalSiteForAppPortlet(AppPortlet portlet) {
Resource parentRes = portlet.getParentResource();
if (parentRes == null) {
return null;
}
//Now we have (possibly) the parent application of the portlet...
if (!(parentRes instanceof Application)) {
return null;
}
//if the parent of this portlet is the PortalSite, return the PortalSite.
//otherwise, try to fetch the parent application's parent PortalSite
if (parentRes instanceof PortalSite) {
return (PortalSite)parentRes;
} else {
return getPortalSiteForApplication((Application)parentRes);
}
}
// Can return null.
public static PortalSite getCurrentPortalSite(HttpServletRequest request) {
String key = "com.arsdigita.workspace.Workspace.currentWorkspace";
PortalSite currentPortalSite = null;
synchronized (request) {
currentPortalSite = (PortalSite) request.getAttribute(key);
if (currentPortalSite == null) {
currentPortalSite = doGetCurrentPortalSite(request);
request.setAttribute(key, currentPortalSite);
}
}
return currentPortalSite;
}
private static PortalSite
doGetCurrentPortalSite(HttpServletRequest request) {
// First, assume that the user is at a PortalSite already,
// since we can save a query if we're right. This logic will
// not make sense if we find that this method is called mostly
// from sub applications of a portal site, since it incurs an
// extra query in that case.
Application application = Application.getCurrentApplication(request);
if (application instanceof PortalSite) {
return (PortalSite) application;
}
while (true) {
if (application == null) {
return null;
}
application = application.getParentApplication();
if (application instanceof PortalSite) {
return (PortalSite) application;
}
}
}
public static PortalSiteCollection getRootPortalSites() {
DataQuery query = SessionManager.getSession().retrieveQuery
("com.arsdigita.workspace.rootWorkspaces");
DataCollection collection =
new DataQueryDataCollectionAdapter(query, "workspace");
query.close();
PortalSiteCollection psc = new PortalSiteCollection(collection);
psc.filterForUnarchived();
return psc;
}
public static PortalSiteCollection getAllRootPortalSites() {
DataQuery query = SessionManager.getSession().retrieveQuery
("com.arsdigita.workspace.rootWorkspaces");
Application app =
Application.retrieveApplicationForPath("/personal-portal/");
if (app != null)
query.setParameter("parentID",app.getID());
DataCollection collection =
new DataQueryDataCollectionAdapter(query, "workspace");
query.close();
return new PortalSiteCollection(collection);
}
public void addRelatedPortalSite(PortalSite portalsite) {
add("relatedWorkspace", portalsite);
}
public void removeRelatedPortalSite(PortalSite portalsite) {
remove("relatedWorkspace", portalsite);
}
public boolean isDirectParticipant(Party party) {
DataAssociationCursor dac =
((DataAssociation) get("participants")).cursor();
dac.addEqualsFilter("id", party.getID());
if (dac.size() == 0) {
return false;
} else {
return true;
}
}
public boolean isParticipant(Party party) {
throw new UnsupportedOperationException();
}
public boolean isDirectMember(Party party) {
Group g = getMemberRole();
return g.hasDirectMemberOrSubgroup(party);
}
public boolean isMember(Party party) {
Group g = getMemberRole();
if (party instanceof User) {
return g.hasMember((User) party);
} else if (party instanceof Group) {
return g.hasSubgroup((Group) party);
} else {
throw new IllegalArgumentException(
"party must be a user or a group");
}
}
/**
* add a participant as a member, the party should not already be a
* participant. adds specified party to member group, and makes the
* specified party a participant
**/
public void addMember(Party member) {
addParticipant(member);
Group g = getMemberRole();
if (member instanceof User) {
User u = (User) member;
g.addMember(u);
} else if (member instanceof Group) {
Group pGroup = (Group) member;
g.addSubgroup(pGroup);
} else {
throw new IllegalArgumentException(
"party must be a user or a group");
}
}
/**
* Adds participant and grants participant read privilege on the workspace.
**/
public void addParticipant(Party participant) {
addParticipant(participant, true);
}
/**
* Adds participant and optionally grants participant read privilege on
* the PortalSite.
*
* @param addDefaultPriv whether or not the read privilege should be
* granted
**/
public void addParticipant(Party participant, boolean addDefaultPriv) {
add("participants", participant);
if (addDefaultPriv) {
PermissionService.grantPermission(new PermissionDescriptor(
PrivilegeDescriptor.READ, this, participant));
}
}
/**
* remove a participant or member from workspace and revoke privileges on
* the Portal Site
**/
public void removeParticipant(Party participant) {
RoleCollection rc = getRoles();
if (participant instanceof User) {
while (rc.next()) {
Role r = rc.getRole();
r.removeMember((User) participant);
r.save();
}
} else if (participant instanceof Group) {
while (rc.next()) {
Role r = rc.getRole();
r.removeSubgroup((Group) participant);
r.save();
}
} else {
throw new IllegalArgumentException(
"received party that was neither user nor group");
}
remove("participants", participant);
// revoke direct grants on this
for (Iterator privIter = PermissionService.getDirectPrivileges
(getOID(), participant.getOID());
privIter.hasNext(); ) {
PrivilegeDescriptor priv = (PrivilegeDescriptor) privIter.next();
PermissionService.revokePermission
(new PermissionDescriptor(priv, this, participant));
}
// revoke direct grants on applications in the portalsite
ApplicationCollection ac = getFullPagePortalSiteApplications();
while (ac.next()) {
OID appOID = new OID(ac.getSpecificObjectType(), ac.getID());
Iterator appPrivs = PermissionService.getDirectPrivileges
(appOID, participant.getOID());
while (appPrivs.hasNext()) {
PrivilegeDescriptor priv = (PrivilegeDescriptor) appPrivs.next();
PermissionService.revokePermission
(new PermissionDescriptor(
priv, appOID, participant.getOID()));
}
}
}
public PartyCollection getParticipants() {
return new PartyCollection(
((DataAssociation) get("participants")).cursor());
}
public long getParticipantCount() {
return ((DataAssociation)get("participants")).cursor().size();
}
public PartyCollection getNonParticipants() {
DataCollection dc =
SessionManager.getSession()
.retrieve("com.arsdigita.kernel.Party");
Filter f = dc.addNotInSubqueryFilter("id", PARTICIPANT_ID_QUERY);
f.set("workspaceID", getID());
return new PartyCollection(dc);
}
/**
* Get a collection of all participants in the Portal Site whose * initial (see {@link getParticipantInitials * getParticipantInitials} for a definition of a participant's * initial) is the specified value.
* * @param initial Single-character string, must be uppercase **/ public PartyCollection getParticipantsWithInitial(String initial) { // Assert.assertNotNull(initial); Assert.exists(initial); // Assert.assertTrue(initial.length() == 1, "Initial needs length 1"); Assert.isTrue(initial.length() == 1, "Initial needs length 1"); // Assert.assertTrue(initial.equals(initial.toUpperCase()), Assert.isTrue(initial.equals(initial.toUpperCase()), "Initial must be uppercase"); DataAssociationCursor dac = ((DataAssociation)get("participants")).cursor(); Filter f = dac.addInSubqueryFilter ("id", "com.arsdigita.workspace.WorkspaceParticipantsWithInitial"); f.set("workspaceID", getID()); f.set("nameInitial", initial); return new PartyCollection(dac); } /** * Returns the member role. This role can be modified directly to change * the parties in the role. **/ public Role getMemberRole() { if (m_memberRole == null) { DataAssociation roles = (DataAssociation) get("roles"); DataAssociationCursor rolesCursor = roles.getDataAssociationCursor(); rolesCursor.addEqualsFilter("type", Role.MEMBER_TYPE); if ( rolesCursor.next() ) { m_memberRole = (Role) DomainObjectFactory. newInstance(rolesCursor.getDataObject()); } rolesCursor.close(); } return m_memberRole; } private void setMemberRole(Role role) { m_memberRole = role; } /** * Returns the collection of roles in this portal site. The returned roles * can be modified directly to change the parties assigned to each role. **/ public RoleCollection getRoles() { return new RoleCollection( ((DataAssociation) get("roles")).cursor(), this); } public RoleCollection getDirectRolesFor(Party p) { DataAssociationCursor dac = ((DataAssociation) get("roles")).cursor(); if (p instanceof User) { Filter f = dac.addInSubqueryFilter( "id", "com.arsdigita.workspace.DirectRolesForUser"); f.set("participantID", p.getID()); } else if (p instanceof Group) { Filter f = dac.addInSubqueryFilter( "id", "com.arsdigita.workspace.DirectRolesForGroup"); f.set("participantID", p.getID()); } else { throw new IllegalArgumentException( "received party that was neither user nor group"); } return new RoleCollection(dac); } /** * Returns the collection of roles in this workspace that the specified * party is contained in. **/ public RoleCollection getRolesFor(Party p) { DataAssociationCursor dac = ((DataAssociation) get("roles")).cursor(); if (p instanceof User) { Filter f = dac.addInSubqueryFilter( "id", "com.arsdigita.workspace.RolesForUser"); f.set("participantID", p.getID()); } else if (p instanceof Group) { Filter f = dac.addInSubqueryFilter( "id", "com.arsdigita.workspace.RolesForGroup"); f.set("participantID", p.getID()); } else { throw new IllegalArgumentException( "received party that was neither user nor group"); } return new RoleCollection(dac); } /////Tab Management public void addPortalTab(PortalTab ptab) { add("workspaceTab",ptab); moveTabToTail(ptab); } public void removePortalTab(PortalTab ptab) { remove("workspaceTab",ptab); } // Can return null. public PortalTabCollection getTabsForPortalSite() { DataAssociation association = (DataAssociation)get("workspaceTab"); if (association == null) { return null; } DataAssociationCursor tabsCursor = association.getDataAssociationCursor(); tabsCursor.addOrder("sortKey"); return new PortalTabCollection(tabsCursor); } public void swapTabWithPrevious(PortalTab ptab) throws com.arsdigita.persistence.PersistenceException { int newKey = ptab.getSortKey() - (SORT_KEY_JUMP + 1); ptab.setSortKey(newKey); ptab.save(); normalizeTabSortKeys(); } public void swapTabWithNext(PortalTab ptab) throws com.arsdigita.persistence.PersistenceException { int newKey = ptab.getSortKey() + (SORT_KEY_JUMP + 1); ptab.setSortKey(newKey); ptab.save(); normalizeTabSortKeys(); } public void moveTabToHead(PortalTab ptab) { ptab.setSortKey(Integer.MIN_VALUE); ptab.save(); normalizeTabSortKeys(); } public void moveTabToTail(PortalTab ptab) { ptab.setSortKey(Integer.MAX_VALUE); ptab.save(); normalizeTabSortKeys(); } public void normalizeTabSortKeys() { PortalTab ptab; PortalTabCollection wtcoll = getTabsForPortalSite(); for (int index = SORT_KEY_JUMP; wtcoll.next(); index += SORT_KEY_JUMP) { ptab = wtcoll.getPortalTab(); ptab.setSortKey(index); ptab.save(); } } // // Member properties // public boolean isReady() { return ((Boolean)get("isReady")).booleanValue(); } public void setReady(boolean isReady) { set("isReady", new Boolean(isReady)); } public boolean isDraft() { return ((Boolean)get("isDraft")).booleanValue(); } public void setDraft(boolean isDraft) { set("isDraft", new Boolean(isDraft)); } public boolean isPersonalizable() { return ((Boolean)get("isPersonalizable")).booleanValue(); } public void setPersonalizable(boolean isPersonalizable) { set("isPersonalizable", new Boolean(isPersonalizable)); } public boolean isSubPortal() { return ((Boolean)get("isSubPortal")).booleanValue(); } public void setIsSubPortal(boolean issubportal) { set("isSubPortal", new Boolean(issubportal)); } public boolean isArchived() { return ((Boolean)get("isArchived")).booleanValue(); } public void setArchived() { set("isArchived", Boolean.TRUE); } public void setUnarchived() { set("isArchived", Boolean.FALSE); } public void setCreationDate( Date cdate) { set("creationDate",cdate); } public void setCreationDate() { Calendar rightNow = GregorianCalendar.getInstance(); Date cdate = rightNow.getTime(); set("creationDate",cdate); } public Date getCreationDate() { return (Date)get("creationDate"); } public void setArchiveDate(Date adate) { set("archiveDate",adate); } public void setArchiveDate() { Calendar rightNow = GregorianCalendar.getInstance(); Date adate = rightNow.getTime(); set("archiveDate",adate); } public Date getArchiveDate() { return (Date)get("archiveDate"); } public void archive() { Party p; //1 - set archive bit setArchived(); //2 - drop permissions PartyCollection pc = getParticipants(); while(pc.next()) { p = pc.getParty(); removeParticipant(p); } //3 set archivedate setArchiveDate(); } public void archiveRecurse() { PortalSite portal; archive(); PortalSiteCollection psc = getChildPortalSites(); psc.filterForUnarchived(); while(psc.next()) { portal = psc.getPortalSite(); portal.archiveRecurse(); } } public void unarchive() { this.setUnarchived(); this.setArchiveDate(); } /** * Returns the Mission statement for the Portal */ public String getMission() { return (String)get("mission"); } /** * Set's the mission statement for a Portal. */ public void setMission(String mission) { set("mission", mission); } /** * Associates a Theme object with this Portal. */ public void setTheme(Theme theme) { set("theme",theme); } /** * Returns the Theme object for this Portal */ public Theme getTheme() { DataObject dobj; dobj = (DataObject)get("theme"); if( dobj == null) return null; else { Theme theme = new Theme(dobj); return theme; } } /** *Get a list of all the distinct "initials" of participants in * a Portal Site.
* *A participant's initial is defined as the first letter of * their family name when the participant is a user (i.e. a * person), and the first letter of the group name if the * participant is a group.
* *The returned Iterator contains the initials in increasing * alphabetical order.
**/ public Iterator getParticipantInitials() { DataQuery query = SessionManager.getSession().retrieveQuery ("com.arsdigita.workspace.WorkspaceParticipantInitials"); query.setParameter("workspaceID", getID()); LinkedList result = new LinkedList(); while (query.next()) { result.add(query.get("initial")); } return result.listIterator(); } public static PortalSite createSubPortal(PortalSite ps, User user) { String urlfrag = "U-" + user.getID().toString(); PortalSite psite = createPortalSite(urlfrag,ps.getDisplayName(),ps); psite.setIsSubPortal(true); //Grab collection of tabs for ps PortalTabCollection ptc = ps.getTabsForPortalSite(); //for each, create duplicate tab for new psite PortalTab ptab; PortalTab newtab; String layout; Portlet portlet; AgentPortlet aportlet; SubPortalTab subtab; PortletCollection portletcollection; while(ptc.next()) { ptab = ptc.getPortalTab(); layout = ptab.getLayout(); if(layout != null) { //If tab layout has a lowercase W or N, make that tab a SubPortalTab. if((layout.indexOf('w') != (-1)) || (layout.indexOf('n') != (-1))) { //create subtab portletcollection = ptab.getPortlets(); for(int i = 0; i < layout.length(); i++) { if(layout.charAt(i) == 'n' || layout.charAt(i) == 'w') portletcollection. addNotEqualsFilter("cellNumber",new Integer(i + 1)); } subtab = SubPortalTab.createSubTab(ptab.getTitle(), psite); subtab.setSuperPortalTab(ptab); subtab.setLayout(ptab.getLayout()); while(portletcollection.next()) { portlet = portletcollection.getPortlet(); aportlet = AgentPortlet.createAgentPortlet(portlet,subtab,subtab); subtab.addPortlet(aportlet,portlet.getCellNumber()); } subtab.setPortalSite(psite); subtab.save(); } else { //create normal tab portletcollection = ptab.getPortlets(); newtab = PortalTab.createTab(ptab.getTitle(), psite); newtab.setLayout(ptab.getLayout()); while(portletcollection.next()) { portlet = portletcollection.getPortlet(); aportlet = AgentPortlet.createAgentPortlet(portlet,newtab,newtab); newtab.addPortlet(aportlet,portlet.getCellNumber()); } newtab.setPortalSite(psite); newtab.save(); } } } psite.save(); return psite; } }