/*******************************************************************************
* Copyright (c) 2000-present Liferay, 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.
*
*******************************************************************************/
package com.liferay.ide.project.core.modules;
import aQute.remote.api.Agent;
import com.liferay.ide.project.core.ProjectCore;
import com.liferay.ide.project.core.util.TargetPlatformUtil;
import com.liferay.ide.server.core.portal.BundleSupervisor;
import com.liferay.ide.server.core.portal.PortalServerBehavior;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.wst.server.core.IServer;
/**
* @author Lovett Li
* @author Simon Jiang
*/
public class ServiceCommand
{
private final IServer _server;
private String _serviceName;
private static final String[] _portalImplExpPackage = new String[] {
"com.liferay.portal.bean",
"com.liferay.portal.cache.thread.local",
"com.liferay.portal.cluster",
"com.liferay.portal.convert.database",
"com.liferay.portal.convert.util",
"com.liferay.portal.dao.jdbc.aop",
"com.liferay.portal.dao.orm.hibernate",
"com.liferay.portal.deploy.hot",
"com.liferay.portal.events",
"com.liferay.portal.freemarker",
"com.liferay.portal.increment",
"com.liferay.portal.messaging.async",
"com.liferay.portal.monitoring.statistics.service",
"com.liferay.portal.plugin",
"com.liferay.portal.resiliency.service",
"com.liferay.portal.search",
"com.liferay.portal.security.access.control",
"com.liferay.portal.security.auth",
"com.liferay.portal.security.lang",
"com.liferay.portal.service.http",
"com.liferay.portal.service.permission",
"com.liferay.portal.servlet",
"com.liferay.portal.servlet.filters.authverifier",
"com.liferay.portal.spring.aop",
"com.liferay.portal.spring.bean",
"com.liferay.portal.spring.context",
"com.liferay.portal.spring.hibernate",
"com.liferay.portal.spring.transaction",
"com.liferay.portal.systemevent",
"com.liferay.portal.template",
"com.liferay.portal.tools",
"com.liferay.portal.upgrade.util",
"com.liferay.portal.upgrade.util.classname",
"com.liferay.portal.upgrade.util.classname.dependency",
"com.liferay.portal.upgrade.v7_0_0",
"com.liferay.portal.upload",
"com.liferay.portal.util",
"com.liferay.portal.xml",
"com.liferay.portlet.asset",
"com.liferay.portlet.asset.model",
"com.liferay.portlet.asset.model.impl",
"com.liferay.portlet.asset.service",
"com.liferay.portlet.asset.service.permission",
"com.liferay.portlet.asset.service.persistence",
"com.liferay.portlet.asset.util",
"com.liferay.portlet.documentlibrary",
"com.liferay.portlet.documentlibrary.action",
"com.liferay.portlet.documentlibrary.antivirus",
"com.liferay.portlet.documentlibrary.convert",
"com.liferay.portlet.documentlibrary.lar",
"com.liferay.portlet.documentlibrary.model",
"com.liferay.portlet.documentlibrary.service",
"com.liferay.portlet.documentlibrary.service.permission",
"com.liferay.portlet.documentlibrary.store",
"com.liferay.portlet.documentlibrary.util",
"com.liferay.portlet.expando.model",
"com.liferay.portlet.expando.service",
"com.liferay.portlet.expando.service.persistence",
"com.liferay.portlet.expando.util",
"com.liferay.portlet.layoutsadmin.display.context",
"com.liferay.portlet.messageboards.model",
"com.liferay.portlet.messageboards.service",
"com.liferay.portlet.messageboards.service.persistence",
"com.liferay.portlet.social.model",
"com.liferay.portlet.social.service",
"com.liferay.portlet.social.service.persistence",
"com.liferay.portlet.trash",
"com.liferay.portlet.trash.model",
"com.liferay.portlet.trash.service",
"com.liferay.portlet.trash.service.persistence",
"com.liferay.portlet.trash.util",
"com.liferay.portlet.usersadmin.search"
};
public ServiceCommand( IServer server )
{
_server = server;
}
public ServiceCommand( IServer server, String serviceName )
{
_serviceName = serviceName;
_server = server;
}
private File checkStaticServicesFile() throws IOException
{
final URL url =
FileLocator.toFileURL( ProjectCore.getDefault().getBundle().getEntry( "OSGI-INF/services-static.json" ) );
final File servicesFile = new File( url.getFile() );
if( servicesFile.exists() )
{
return servicesFile;
}
throw new FileNotFoundException( "can't find static services file services-static.json" );
}
public ServiceContainer execute() throws Exception
{
BundleSupervisor supervisor = null;
ServiceContainer result;
if( _server == null )
{
return getServiceFromTargetPlatform();
}
try
{
PortalServerBehavior serverBehavior =
(PortalServerBehavior) _server.loadAdapter( PortalServerBehavior.class, null );
supervisor = serverBehavior.getBundleSupervisor();
if( supervisor == null )
{
return getServiceFromTargetPlatform();
}
if( !supervisor.getAgent().redirect( Agent.COMMAND_SESSION ) )
{
return getServiceFromTargetPlatform();
}
if( _serviceName == null )
{
String[] services = getServices( supervisor );
result = new ServiceContainer( Arrays.asList( services ) );
}
else
{
String[] serviceBundle = getServiceBundle( _serviceName, supervisor );
result = new ServiceContainer( serviceBundle[0], serviceBundle[1], serviceBundle[2] );
}
}
finally
{
supervisor.getAgent().redirect( Agent.NONE );
}
return result;
}
private ServiceContainer getServiceFromTargetPlatform() throws Exception
{
ServiceContainer result;
if( _serviceName == null )
{
result = TargetPlatformUtil.getServicesList();
}
else
{
result = TargetPlatformUtil.getServiceBundle( _serviceName );
}
return result;
}
private String[] getServiceBundle( String serviceName, BundleSupervisor supervisor ) throws Exception
{
String[] serviceBundleInfo;
String bundleGroup = "";
String bundleName;
String bundleVersion;
supervisor.getAgent().stdin( "packages " + serviceName.substring( 0, serviceName.lastIndexOf( "." ) ) );
if( supervisor.getOutInfo().startsWith( "No exported packages" ) )
{
supervisor.getAgent().stdin(
"services " + "(objectClass=" + serviceName + ")" + " | grep \"Registered by bundle:\" " );
serviceBundleInfo = parseRegisteredBundle( supervisor.getOutInfo() );
}
else
{
serviceBundleInfo = parseSymbolicName( supervisor.getOutInfo() );
}
bundleName = serviceBundleInfo[0];
bundleVersion = serviceBundleInfo[1];
if( bundleName.equals( "org.eclipse.osgi,system.bundle" ) )
{
bundleGroup = "com.liferay.portal";
}
else if( bundleName.startsWith( "com.liferay" ) )
{
bundleGroup = "com.liferay";
}
else
{
int ordinalIndexOf = StringUtils.ordinalIndexOf( bundleName, ".", 3 );
if(ordinalIndexOf != -1)
{
bundleGroup = bundleName.substring( 0, ordinalIndexOf );
}else{
ordinalIndexOf = StringUtils.ordinalIndexOf( bundleName, ".", 2 );
if(ordinalIndexOf != -1){
bundleGroup = bundleName.substring( 0, ordinalIndexOf );
}
}
}
return new String[] { bundleGroup, bundleName, bundleVersion };
}
private String[] getServices( BundleSupervisor supervisor ) throws Exception
{
supervisor.getAgent().stdin( "services" );
return parseService( supervisor.getOutInfo() );
}
private void updateServicesStaticFile( final String[] servicesList, final BundleSupervisor supervisor ) throws Exception
{
final File servicesFile = checkStaticServicesFile();
final ObjectMapper mapper = new ObjectMapper();
final Map<String, String[]> map = new LinkedHashMap<>();
final Job job = new WorkspaceJob( "Update services static file...")
{
@Override
public IStatus runInWorkspace( IProgressMonitor monitor )
{
try
{
for( String serviceName : servicesList )
{
if( monitor.isCanceled() )
{
return Status.CANCEL_STATUS;
}
String[] serviceBundle = getServiceBundle( serviceName, supervisor );
if( serviceBundle != null )
{
map.put( serviceName, serviceBundle );
}
}
mapper.writeValue( servicesFile, map );
}
catch( Exception e )
{
return Status.CANCEL_STATUS;
}
finally
{
if( supervisor != null )
{
try
{
supervisor.getAgent().redirect( Agent.NONE );
}
catch( Exception e )
{
// ignore error
}
}
}
return Status.OK_STATUS;
}
};
job.schedule();
}
private String[] parseRegisteredBundle( String serviceName )
{
if( serviceName.startsWith( "false" ) )
{
return null;
}
String str = serviceName.substring( 0, serviceName.indexOf( "[" ) );
str = str.replaceAll( "\"Registered by bundle:\"", "" ).trim();
String[] result = str.split( "_" );
if( result.length == 2 )
{
return result;
}
return null;
}
private String[] parseService( String outinfo )
{
final Pattern pattern = Pattern.compile( "(?<=\\{)(.+?)(?=\\})" );
final Matcher matcher = pattern.matcher( outinfo );
final List<String> ls = new ArrayList<>();
while( matcher.find() )
{
ls.add( matcher.group() );
}
Iterator<String> iterator = ls.iterator();
while( iterator.hasNext() )
{
String serviceName = iterator.next();
if( serviceName.contains( "bundle.id=" ) || serviceName.contains( "service.id=" ) ||
serviceName.contains( "=" ) )
{
iterator.remove();
}
}
final List<String> listservice = new ArrayList<>();
for( String bs : ls )
{
if( bs.split( "," ).length > 1 )
{
for( String bbs : bs.split( "," ) )
{
listservice.add( bbs.trim() );
}
}
else
{
listservice.add( bs );
}
}
final Set<String> set = new HashSet<String>();
final List<String> newList = new ArrayList<>();
for( Iterator<String> iter = listservice.iterator(); iter.hasNext(); )
{
String element = iter.next();
if( set.add( element ) )
{
newList.add( element );
}
}
Collections.sort( newList );
Iterator<String> newListIterator = newList.iterator();
while( newListIterator.hasNext() )
{
String serviceName = newListIterator.next();
for( String packageName : _portalImplExpPackage )
{
if( serviceName.startsWith( packageName ) )
{
newListIterator.remove();
break;
}
}
}
return newList.toArray( new String[0] );
}
private String[] parseSymbolicName( String info )
{
final int symbolicIndex = info.indexOf( "bundle-symbolic-name" );
final int versionIndex = info.indexOf( "version:Version" );
String symbolicName;
String version;
if( symbolicIndex != -1 && versionIndex != -1 )
{
symbolicName = info.substring( symbolicIndex, info.indexOf( ";", symbolicIndex ) );
version = info.substring( versionIndex, info.indexOf( ";", versionIndex ) );
final Pattern p = Pattern.compile( "\"([^\"]*)\"" );
Matcher m = p.matcher( symbolicName );
while( m.find() )
{
symbolicName = m.group( 1 );
}
m = p.matcher( version );
while( m.find() )
{
version = m.group( 1 );
}
return new String[] { symbolicName, version };
}
return null;
}
}