/*******************************************************************************
* Copyright 2011 Google Inc. All Rights Reserved.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.google.gdt.eclipse.designer.refactoring;
import com.google.common.collect.Maps;
import com.google.gdt.eclipse.designer.model.module.EntryPointElement;
import com.google.gdt.eclipse.designer.model.module.GwtDocumentEditContext;
import com.google.gdt.eclipse.designer.model.module.ServletElement;
import com.google.gdt.eclipse.designer.model.web.WebDocumentEditContext;
import com.google.gdt.eclipse.designer.model.web.WebUtils;
import com.google.gdt.eclipse.designer.util.DefaultModuleDescription;
import com.google.gdt.eclipse.designer.util.ModuleDescription;
import com.google.gdt.eclipse.designer.util.Utils;
import org.eclipse.wb.internal.core.utils.refactoring.RefactoringUtils;
import org.eclipse.wb.internal.core.utils.xml.DocumentElement;
import org.eclipse.wb.internal.core.utils.xml.DocumentModelVisitor;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeHierarchy;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.ltk.core.refactoring.Change;
import org.apache.commons.lang.StringUtils;
import java.util.Map;
/**
* GWT refactoring utilities.
*
* @author scheglov_ke
* @coverage gwt.refactoring.participants
*/
public class GwtRefactoringUtils extends RefactoringUtils {
////////////////////////////////////////////////////////////////////////////
//
// GWT module refactoring utils
//
////////////////////////////////////////////////////////////////////////////
/**
* @return {@link Change} for changing entry point from existing {@link IType} to type with new
* name.
*/
public static Change module_replaceEntryPoint(IType type, final String newTypeName)
throws Exception {
final String oldTypeName = type.getFullyQualifiedName();
return modifyModule(type, new DocumentModelVisitor() {
@Override
public void endVisit(DocumentElement element) {
if (element instanceof EntryPointElement) {
EntryPointElement entryPointElement = (EntryPointElement) element;
if (entryPointElement.getClassName().equals(oldTypeName)) {
entryPointElement.setClassName(newTypeName);
}
}
}
});
}
/**
* @return {@link Change} for changing servlet from existing {@link IType} to type with new name.
*/
public static Change module_replaceServletClass(IType type, final String newTypeName)
throws Exception {
final String oldTypeName = type.getFullyQualifiedName();
return modifyModule(type, new DocumentModelVisitor() {
@Override
public void endVisit(DocumentElement element) {
if (element instanceof ServletElement) {
ServletElement servletElement = (ServletElement) element;
if (servletElement.getClassName().equals(oldTypeName)) {
servletElement.setClassName(newTypeName);
}
}
}
});
}
/**
* @return {@link Change} for changing path of servlet with given {@link IType} and path to new
* path.
*/
public static Change module_replaceServletPath(IType type,
final String oldPath,
final String newPath) throws Exception {
final String oldTypeName = type.getFullyQualifiedName();
return modifyModule(type, new DocumentModelVisitor() {
@Override
public void endVisit(DocumentElement element) {
if (element instanceof ServletElement) {
ServletElement servletElement = (ServletElement) element;
if (servletElement.getClassName().equals(oldTypeName)
&& servletElement.getPath().equals(oldPath)) {
servletElement.setPath(newPath);
}
}
}
});
}
/**
* @return {@link Change} for removing servlet with given {@link IType}.
*/
public static Change module_removeServlet(IType type) throws Exception {
final String typeName = type.getFullyQualifiedName();
return modifyModule(type, new DocumentModelVisitor() {
@Override
public void endVisit(DocumentElement element) {
if (element instanceof ServletElement) {
ServletElement servletElement = (ServletElement) element;
if (servletElement.getClassName().equals(typeName)) {
servletElement.remove();
}
}
}
});
}
/**
* @return {@link Change} for removing <code>EntryPoint</code> with given {@link IType}.
*/
public static Change module_removeEntryPoint(IType type) throws Exception {
final String typeName = type.getFullyQualifiedName();
return modifyModule(type, new DocumentModelVisitor() {
@Override
public void endVisit(DocumentElement element) {
if (element instanceof EntryPointElement) {
EntryPointElement entryPointElement = (EntryPointElement) element;
if (entryPointElement.getClassName().equals(typeName)) {
entryPointElement.remove();
}
}
}
});
}
////////////////////////////////////////////////////////////////////////////
//
// web.xml refactoring utils
//
////////////////////////////////////////////////////////////////////////////
/**
* @return {@link Change} for changing servlet from existing {@link IType} to type with new name.
*/
public static Change web_replaceServletClass(IType type, final String newTypeName)
throws Exception {
final String oldTypeName = type.getFullyQualifiedName();
return modifyWeb(type, new DocumentModelVisitor() {
@Override
public void endVisit(DocumentElement element) {
if (element instanceof com.google.gdt.eclipse.designer.model.web.ServletElement) {
com.google.gdt.eclipse.designer.model.web.ServletElement servlet =
(com.google.gdt.eclipse.designer.model.web.ServletElement) element;
if (servlet.getClassName().equals(oldTypeName)) {
servlet.setClassName(newTypeName);
}
}
}
});
}
/**
* @return {@link Change} for changing name of servlet in "servlet" element.
*/
public static Change web_replaceServletPath(IType type, final String oldName, final String newName)
throws Exception {
return modifyWeb(type, new DocumentModelVisitor() {
@Override
public void endVisit(DocumentElement element) {
if (element instanceof com.google.gdt.eclipse.designer.model.web.ServletElement) {
com.google.gdt.eclipse.designer.model.web.ServletElement servlet =
(com.google.gdt.eclipse.designer.model.web.ServletElement) element;
if (servlet.getName().equals(oldName)) {
servlet.setName(newName);
}
}
if (element instanceof com.google.gdt.eclipse.designer.model.web.ServletMappingElement) {
com.google.gdt.eclipse.designer.model.web.ServletMappingElement mapping =
(com.google.gdt.eclipse.designer.model.web.ServletMappingElement) element;
if (mapping.getName().equals(oldName)) {
mapping.setName(newName);
}
String pattern = mapping.getPattern();
if (pattern.endsWith("/" + oldName)) {
pattern = StringUtils.removeEnd(pattern, oldName) + newName;
mapping.setPattern(pattern);
}
}
}
});
}
/**
* @return {@link Change} for removing servlet with given {@link IType}.
*/
public static Change web_removeServlet(IType type) throws Exception {
final String typeName = type.getFullyQualifiedName();
return modifyWeb(type, new DocumentModelVisitor() {
Map<String, com.google.gdt.eclipse.designer.model.web.ServletMappingElement> mappingElements =
Maps.newTreeMap();
String servletNameToRemove;
@Override
public void endVisit(DocumentElement element) {
if (element instanceof com.google.gdt.eclipse.designer.model.web.ServletElement) {
com.google.gdt.eclipse.designer.model.web.ServletElement servlet =
(com.google.gdt.eclipse.designer.model.web.ServletElement) element;
if (servlet.getClassName().equals(typeName)) {
servlet.remove();
servletNameToRemove = servlet.getName();
removeServletMapping();
}
}
if (element instanceof com.google.gdt.eclipse.designer.model.web.ServletMappingElement) {
com.google.gdt.eclipse.designer.model.web.ServletMappingElement mapping =
(com.google.gdt.eclipse.designer.model.web.ServletMappingElement) element;
mappingElements.put(mapping.getName(), mapping);
removeServletMapping();
}
}
private void removeServletMapping() {
if (servletNameToRemove != null) {
if (mappingElements.containsKey(servletNameToRemove)) {
mappingElements.get(servletNameToRemove).remove();
}
}
}
});
}
////////////////////////////////////////////////////////////////////////////
//
// XML change internal utils
//
////////////////////////////////////////////////////////////////////////////
/**
* @return {@link Change} for modifications in module file done by {@link DocumentModelVisitor}.
*/
private static Change modifyModule(IType type, DocumentModelVisitor visitor) throws Exception {
ModuleDescription moduleDescription = Utils.getSingleModule(type);
if (moduleDescription instanceof DefaultModuleDescription) {
IFile moduleFile = ((DefaultModuleDescription) moduleDescription).getFile();
GwtDocumentEditContext context = new GwtDocumentEditContext(moduleFile);
return modifyXML(moduleFile, visitor, context);
}
return null;
}
/**
* @return {@link Change} for modifications in web.xml file done by {@link DocumentModelVisitor}.
*/
private static Change modifyWeb(IType type, DocumentModelVisitor visitor) throws Exception {
IProject project = type.getCompilationUnit().getUnderlyingResource().getProject();
String webFolderName = WebUtils.getWebFolderName(project);
IFile webFile = project.getFile(webFolderName + "/WEB-INF/web.xml");
if (webFile.exists()) {
WebDocumentEditContext context = new WebDocumentEditContext(webFile);
return modifyXML(webFile, visitor, context);
}
return null;
}
////////////////////////////////////////////////////////////////////////////
//
// RemoteService utils
//
////////////////////////////////////////////////////////////////////////////
/**
* @return "async" type for given RemoteService type, or <code>null</code>.
*/
public static IType getServiceAsyncType(IType serviceType, IProgressMonitor pm)
throws JavaModelException {
String asyncTypeName = serviceType.getFullyQualifiedName() + "Async";
return serviceType.getJavaProject().findType(asyncTypeName, pm);
}
/**
* @return single "impl" type for given RemoteService type, or <code>null</code>.
*/
public static IType getServiceImplType(IType serviceType, IProgressMonitor pm)
throws JavaModelException {
ITypeHierarchy hierarchy = serviceType.newTypeHierarchy(pm);
IType[] subtypes = hierarchy.getAllSubtypes(serviceType);
return subtypes.length == 1 ? subtypes[0] : null;
}
}