Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dennis Ushakov
2015-03-13 18:14:38 +03:00
205 changed files with 5617 additions and 5844 deletions
+10 -1
View File
@@ -973,6 +973,15 @@ Function un.ConfirmDeleteSettings
!insertmacro INSTALLOPTIONS_WRITE "DeleteSettings.ini" "Field 3" "Text" "$(text_delete_settings)"
!insertmacro INSTALLOPTIONS_WRITE "DeleteSettings.ini" "Field 4" "Text" "$(confirm_delete_caches)"
!insertmacro INSTALLOPTIONS_WRITE "DeleteSettings.ini" "Field 5" "Text" "$(confirm_delete_settings)"
StrCmp "${UNINSTALL_WEB_PAGE}" "feedback_web_page" hide_feedback_checkbox done
hide_feedback_checkbox:
; do not show feedback web page checkbox through products uninstall.
push $R1
!insertmacro INSTALLOPTIONS_READ $R1 "DeleteSettings.ini" "Settings" "NumFields"
IntOp $R1 $R1 - 1
!insertmacro INSTALLOPTIONS_WRITE "DeleteSettings.ini" "Settings" "NumFields" "$R1"
pop $R1
done:
!insertmacro INSTALLOPTIONS_DISPLAY "DeleteSettings.ini"
FunctionEnd
@@ -1181,9 +1190,9 @@ remove_IntelliJIdeaProjectFile:
done:
DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_WITH_VER}"
; UNCOMMENT THIS IN RELEASE BUILD
StrCmp "${UNINSTALL_WEB_PAGE}" "feedback_web_page" end_of_uninstall
!insertmacro INSTALLOPTIONS_READ $R3 "DeleteSettings.ini" "Field 6" "State"
StrCmp "$R3" "0" end_of_uninstall
StrCmp "${UNINSTALL_WEB_PAGE}" "NotRequired" end_of_uninstall
ExecShell "" "${UNINSTALL_WEB_PAGE}"
end_of_uninstall:
SectionEnd
+2
View File
@@ -6,6 +6,8 @@
!define PRODUCT_UNINST_ICON_FILE "idea_uninst.ico"
!define PRODUCT_LOGO_FILE "logo.bmp"
!define PRODUCT_HEADER_FILE "headerlogo.bmp"
!define ASSOCIATION ".java"
!define UNINSTALL_WEB_PAGE "https://www.jetbrains.com/idea/uninstall/?edition=IU-__VERSION_MAJOR__.__VERSION_MINOR__"
; if SHOULD_SET_DEFAULT_INSTDIR != 0 then default installation directory will be directory where highest-numbered IDEA build has been installed
; set to 1 for release build
+2
View File
@@ -6,6 +6,8 @@
!define PRODUCT_UNINST_ICON_FILE "idea_CEuninst.ico"
!define PRODUCT_LOGO_FILE "logoCE.bmp"
!define PRODUCT_HEADER_FILE "headerlogoCE.bmp"
!define ASSOCIATION ".java"
!define UNINSTALL_WEB_PAGE "https://www.jetbrains.com/idea/uninstall/?edition=IC-__VERSION_MAJOR__.__VERSION_MINOR__"
; if SHOULD_SET_DEFAULT_INSTDIR != 0 then default installation directory will be directory where highest-numbered IDEA build has been installed
; set to 1 for release build
@@ -26,10 +26,7 @@ import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
import com.intellij.debugger.engine.jdi.ThreadReferenceProxy;
import com.intellij.debugger.engine.requests.MethodReturnValueWatcher;
import com.intellij.debugger.engine.requests.RequestManagerImpl;
import com.intellij.debugger.impl.DebuggerContextImpl;
import com.intellij.debugger.impl.DebuggerSession;
import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.debugger.impl.PrioritizedTask;
import com.intellij.debugger.impl.*;
import com.intellij.debugger.jdi.StackFrameProxyImpl;
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
@@ -89,6 +86,7 @@ import javax.swing.*;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class DebugProcessImpl extends UserDataHolderBase implements DebugProcess {
@@ -1852,7 +1850,7 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
final Semaphore semaphore = new Semaphore();
semaphore.down();
final Ref<Boolean> connectorIsReady = Ref.create(false);
final AtomicBoolean connectorIsReady = new AtomicBoolean(false);
myDebugProcessDispatcher.addListener(new DebugProcessAdapter() {
@Override
public void connectorIsReady() {
@@ -1890,17 +1888,17 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
}
else {
fail();
if (myExecutionResult != null || !connectorIsReady.get()) {
// propagate exception only in case we succeeded to obtain execution result,
// otherwise if the error is induced by the fact that there is nothing to debug, and there is no need to show
// this problem to the user
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
DebuggerInvocationUtil.swingInvokeLater(myProject, new Runnable() {
@Override
public void run() {
// propagate exception only in case we succeeded to obtain execution result,
// otherwise if the error is induced by the fact that there is nothing to debug, and there is no need to show
// this problem to the user
if (myExecutionResult != null || !connectorIsReady.get()) {
ExecutionUtil.handleExecutionError(myProject, ToolWindowId.DEBUG, sessionName, e);
}
});
}
}
});
break;
}
}
@@ -88,6 +88,7 @@ public class HighlightMethodUtil {
PsiMethod superMethod = superMethodSignature.getMethod();
if (method.hasModifierProperty(PsiModifier.ABSTRACT) && !MethodSignatureUtil.isSuperMethod(superMethod, method)) continue;
if (!PsiUtil.isAccessible(containingFile.getProject(), superMethod, method, null)) continue;
if (!includeRealPositionInfo && MethodSignatureUtil.isSuperMethod(superMethod, method)) continue;
HighlightInfo info = isWeaker(method, modifierList, accessModifier, accessLevel, superMethod, includeRealPositionInfo);
if (info != null) return info;
}
@@ -37,7 +37,9 @@ import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.util.PropertyUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -120,12 +122,17 @@ public class CreatePropertyFromUsageFix extends CreateFromUsageBaseFix implement
private final String myDefaultFieldName;
private final PsiField myField;
private final PsiClass myClass;
private final PsiType[] myExpectedTypes;
private final List<SmartTypePointer> myExpectedTypes;
public FieldExpression(PsiField field, PsiClass aClass, PsiType[] expectedTypes) {
public FieldExpression(final PsiField field, PsiClass aClass, PsiType[] expectedTypes) {
myField = field;
myClass = aClass;
myExpectedTypes = expectedTypes;
myExpectedTypes = ContainerUtil.map(expectedTypes, new Function<PsiType, SmartTypePointer>() {
@Override
public SmartTypePointer fun(PsiType type) {
return SmartTypePointerManager.getInstance(field.getProject()).createSmartTypePointer(type);
}
});
myDefaultFieldName = field.getName();
}
@@ -143,12 +150,11 @@ public class CreatePropertyFromUsageFix extends CreateFromUsageBaseFix implement
public LookupElement[] calculateLookupItems(ExpressionContext context) {
Set<LookupElement> set = new LinkedHashSet<LookupElement>();
set.add(JavaLookupElementBuilder.forField(myField).withTypeText(myField.getType().getPresentableText()));
PsiField[] fields = myClass.getFields();
for (PsiField otherField : fields) {
for (PsiField otherField : myClass.getFields()) {
if (!myDefaultFieldName.equals(otherField.getName())) {
PsiType otherType = otherField.getType();
for (PsiType type : myExpectedTypes) {
if (type.equals(otherType)) {
for (SmartTypePointer pointer : myExpectedTypes) {
if (otherType.equals(pointer.getType())) {
set.add(JavaLookupElementBuilder.forField(otherField).withTypeText(otherType.getPresentableText()));
}
}
@@ -0,0 +1,15 @@
class F {
public void f() {}
}
class E extends F {
@Override
<error descr="'f()' in 'E' clashes with 'f()' in 'F'; attempting to assign weaker access privileges ('protected'); was 'public'">protected</error> void f() {
super.f();
}
}
class EE extends E {
}
@@ -467,6 +467,10 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false);
}
public void testDontReportWeakerVisibilityProblemUpInHierarchy() throws Exception {
doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false);
}
public void testJavaUtilCollections_NoVerify() throws Exception {
PsiClass collectionsClass = getJavaFacade().findClass("java.util.Collections", GlobalSearchScope.moduleWithLibrariesScope(getModule()));
assertNotNull(collectionsClass);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -96,6 +96,16 @@ public class MockApplicationEx extends MockApplication implements ApplicationEx
return false;
}
@Override
public boolean runProcessWithProgressSynchronouslyInReadAction(@Nullable Project project,
@NotNull String progressTitle,
boolean canBeCanceled,
String cancelText,
JComponent parentComponent,
@NotNull Runnable process) {
return false;
}
@NotNull
@Override
public <T> T[] getExtensions(@NotNull final ExtensionPointName<T> extensionPointName) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -65,6 +65,21 @@ public interface ApplicationEx extends Application {
void doNotSave(boolean value);
boolean isDoNotSave();
/**
* Executes {@code process} in a separate thread in the application thread pool (see {@link #executeOnPooledThread(Runnable)}).
* The process is run inside read action (see {@link #runReadAction(Runnable)})
* It is guaranteed that no other read or write action is run before the process start running.
* If the process is running for too long, a progress window shown with {@code progressTitle} and a button with {@code cancelText}.
* This method can be called from the EDT only.
* @return true if process run successfully and was not canceled.
*/
boolean runProcessWithProgressSynchronouslyInReadAction(@Nullable Project project,
@NotNull String progressTitle,
boolean canBeCanceled,
String cancelText,
JComponent parentComponent,
@NotNull Runnable process);
/**
* @param force if true, no additional confirmations will be shown. The application is guaranteed to exit
* @param exitConfirmed if true, suppresses any shutdown confirmation. However, if there are any background processes or tasks running,
@@ -112,7 +127,7 @@ public interface ApplicationEx extends Application {
void runEdtSafeAction(@NotNull Runnable runnable);
/**
* Grab the lock and run the action, in a non-blocking fashion
* Tries to acquire the read lock and run the {@code action}
*
* @return true if action was run while holding the lock, false if was unable to get the lock and action was not run
*/
@@ -15,7 +15,6 @@
*/
package com.intellij.ide.passwordSafe.impl.providers.masterKey;
import com.intellij.ide.TypePresentationService;
import com.intellij.ide.passwordSafe.HelpID;
import com.intellij.openapi.ui.ValidationInfo;
import com.intellij.util.ui.UIUtil;
@@ -28,7 +27,7 @@ public class EnterPasswordComponent extends PasswordComponentBase {
public EnterPasswordComponent(@NotNull MasterKeyPasswordSafe safe, @NotNull Class<?> requestor) {
super(safe, "Enter");
String requestorName = TypePresentationService.getDefaultTypeName(requestor); // requestor.getSimpleName();
String requestorName = getRequestorTitle(requestor);
myPromptLabel.setText("<html><br>Master password is required to unlock the password database.<br>" +
"The password database will be unlocked during this session<br>" +
"for all subsystems.<br>" +
@@ -1,57 +0,0 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.intellij.ide.passwordSafe.impl.providers.masterKey;
import com.intellij.ui.DocumentAdapter;
import com.intellij.util.Processor;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import java.util.Arrays;
/**
* Utilities for master key provider
*/
class MasterKeyUtils {
/**
* The private constructor for utility class
*/
private MasterKeyUtils() {
}
/**
* Match passwords
*
* @param passwordField1 the first password field
* @param passwordField2 the second password field
* @param setError the callback used to set or to clear an error
*/
static void matchPasswords(final JPasswordField passwordField1, final JPasswordField passwordField2, final Processor<String> setError) {
DocumentAdapter l = new DocumentAdapter() {
@Override
protected void textChanged(DocumentEvent e) {
if (Arrays.equals(passwordField1.getPassword(), passwordField2.getPassword())) {
setError.process(null);
}
else {
setError.process("The new password and confirm passwords do not match.");
}
}
};
passwordField1.getDocument().addDocumentListener(l);
passwordField2.getDocument().addDocumentListener(l);
}
}
@@ -63,7 +63,7 @@ public class MasterPasswordDialog extends DialogWrapper {
}
if (!enterMasterPasswordDialog(project, safe, requestor).showAndGet()) {
throw new MasterPasswordUnavailableException("Cancelled by user");
throw new MasterPasswordUnavailableException(PasswordComponentBase.getRequestorTitle(requestor) + ": Cancelled by user");
}
}
@@ -16,6 +16,7 @@
package com.intellij.ide.passwordSafe.impl.providers.masterKey;
import com.intellij.icons.AllIcons;
import com.intellij.ide.TypePresentationService;
import com.intellij.openapi.ui.ValidationInfo;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
@@ -100,4 +101,9 @@ public abstract class PasswordComponentBase {
}
return null;
}
@NotNull
public static String getRequestorTitle(@NotNull Class<?> requestor) {
return TypePresentationService.getDefaultTypeName(requestor);
}
}
@@ -77,10 +77,7 @@ import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -644,6 +641,75 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
return !progress.isCanceled();
}
@Override
public boolean runProcessWithProgressSynchronouslyInReadAction(@Nullable final Project project, @NotNull final String progressTitle,
final boolean canBeCanceled,
final String cancelText, final JComponent parentComponent,
@NotNull final Runnable process) {
assertIsDispatchThread();
boolean writeAccessAllowed = isInsideWriteActionEDTOnly();
if (writeAccessAllowed // Disallow running process in separate thread from under write action.
// The thread will deadlock trying to get read action otherwise.
) {
throw new IncorrectOperationException("Starting process with progress from within write action makes no sense");
}
final ProgressWindow progress = new ProgressWindow(canBeCanceled, false, project, parentComponent, cancelText);
// in case of abrupt application exit when 'ProgressManager.getInstance().runProcess(process, progress)' below
// does not have a chance to run, and as a result the progress won't be disposed
Disposer.register(this, progress);
progress.setTitle(progressTitle);
final CountDownLatch readActionAcquired = new CountDownLatch(1);
final CountDownLatch modalityEntered = new CountDownLatch(1);
executeOnPooledThread(new Runnable() {
@Override
public void run() {
try {
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
readActionAcquired.countDown();
waitFor(modalityEntered);
ProgressManager.getInstance().runProcess(process, progress);
}
});
}
catch (ProcessCanceledException e) {
progress.cancel();
// ok to ignore.
}
catch (RuntimeException e) {
progress.cancel();
throw e;
}
}
});
waitFor(readActionAcquired);
progress.startBlocking(new Runnable() {
@Override
public void run() {
modalityEntered.countDown();
}
});
LOG.assertTrue(!progress.isRunning());
return !progress.isCanceled();
}
private static void waitFor(@NotNull CountDownLatch modalityEntered) {
try {
modalityEntered.await();
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
@Override
public void invokeAndWait(@NotNull Runnable runnable, @NotNull ModalityState modalityState) {
Status status = getStatus();
@@ -24,7 +24,6 @@ import com.intellij.openapi.options.ex.SortedConfigurableGroup;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.*;
import com.intellij.ui.components.GradientViewport;
import com.intellij.ui.treeStructure.CachingSimpleNode;
@@ -34,8 +33,6 @@ import com.intellij.ui.treeStructure.SimpleTreeStructure;
import com.intellij.ui.treeStructure.filtered.FilteringTreeBuilder;
import com.intellij.ui.treeStructure.filtered.FilteringTreeStructure;
import com.intellij.util.ArrayUtil;
import com.intellij.util.NullableFunction;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.ButtonlessScrollBarUI;
import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.TextTransferable;
@@ -115,24 +112,13 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
@Nullable
@Override
protected Transferable createTransferable(JComponent c) {
final TreePath path = myTree.getPathForRow(myTree.getLeadSelectionRow());
if (path != null) {
final String pathInTheTree = StringUtil.join(ContainerUtil.mapNotNull(path.getPath(), new NullableFunction<Object, String>() {
@Nullable
@Override
public String fun(Object o) {
if (o == path.getPath()[0]) {
return null;
}
else {
final MyNode node = extractNode(o);
return node != null ? node.myDisplayName : null;
}
}
}), " | ");
if (!StringUtil.isEmpty(pathInTheTree)) {
return new TextTransferable("File | Settings | " + pathInTheTree);
MyNode node = extractNode(myTree.getPathForRow(myTree.getLeadSelectionRow()));
if (node != null) {
StringBuilder sb = new StringBuilder("File | Settings");
for (String name : getPathNames(node)) {
sb.append(" | ").append(name);
}
return new TextTransferable(sb.toString());
}
return null;
}
@@ -206,8 +192,11 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
@NotNull
String[] getPathNames(Configurable configurable) {
return getPathNames(findNode(configurable));
}
private static String[] getPathNames(MyNode node) {
ArrayDeque<String> path = new ArrayDeque<String>();
MyNode node = findNode(configurable);
while (node != null) {
path.push(node.myDisplayName);
SimpleNode parent = node.getParent();
@@ -103,7 +103,7 @@ public class ProgressWindow extends ProgressIndicatorBase implements BlockingPro
Disposer.register(this, myDialog);
myFocusTrackback.registerFocusComponent(myDialog.getPanel());
addStateDelegate(new AbstractProgressIndicatorExBase(){
addStateDelegate(new AbstractProgressIndicatorExBase() {
@Override
public void cancel() {
super.cancel();
@@ -186,6 +186,10 @@ public class ProgressWindow extends ProgressIndicatorBase implements BlockingPro
@Override
public void startBlocking() {
startBlocking(EmptyRunnable.getInstance());
}
public void startBlocking(@NotNull Runnable init) {
ApplicationManager.getApplication().assertIsDispatchThread();
synchronized (this) {
LOG.assertTrue(!isRunning());
@@ -193,6 +197,7 @@ public class ProgressWindow extends ProgressIndicatorBase implements BlockingPro
}
enterModality();
init.run();
IdeEventQueue.getInstance().pumpEventsForHierarchy(myDialog.myPanel, new Condition<AWTEvent>() {
@Override
@@ -214,7 +214,8 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
@Deprecated
public DialogWrapperPeerImpl(@NotNull DialogWrapper wrapper,final Window owner, final boolean canBeParent, final boolean applicationModalIfPossible) {
this(wrapper, owner, canBeParent, applicationModalIfPossible ? DialogWrapper.IdeModalityType.IDE : DialogWrapper.IdeModalityType.PROJECT);
this(wrapper, owner, canBeParent,
applicationModalIfPossible ? DialogWrapper.IdeModalityType.IDE : DialogWrapper.IdeModalityType.PROJECT);
}
@Override
@@ -301,10 +302,6 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
}
}
private boolean isProgressDialog() {
return myWrapper.isModalProgress();
}
@Override
@Nullable
public Container getContentPane() {
@@ -452,11 +449,9 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
ApplicationManager.getApplication() != null ? (CommandProcessorEx)CommandProcessor.getInstance() : null;
final boolean appStarted = commandProcessor != null;
if (myDialog.isModal() && !isProgressDialog()) {
if (appStarted) {
commandProcessor.enterModal();
LaterInvocator.enterModal(myDialog);
}
if (myDialog.isModal() && appStarted) {
commandProcessor.enterModal();
LaterInvocator.enterModal(myDialog);
}
if (appStarted) {
@@ -467,11 +462,9 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
myDialog.show();
}
finally {
if (myDialog.isModal() && !isProgressDialog()) {
if (appStarted) {
commandProcessor.leaveModal();
LaterInvocator.leaveModal(myDialog);
}
if (myDialog.isModal() && appStarted) {
commandProcessor.leaveModal();
LaterInvocator.leaveModal(myDialog);
}
myDialog.getFocusManager().doWhenFocusSettlesDown(result.createSetDoneRunnable());
@@ -1,3 +1,18 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 org.jetbrains.io;
import com.google.gson.JsonParseException;
@@ -768,6 +783,16 @@ public final class JsonReaderEx implements Closeable {
return peek() == JsonToken.STRING ? nextString() : null;
}
public String nextNullableString() {
if (peek() == JsonToken.NULL) {
nextNull();
return null;
}
else {
return nextString();
}
}
public String nextString() {
return nextString(false);
}
@@ -18,6 +18,7 @@ package com.intellij.application;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ex.ApplicationEx;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
@@ -29,6 +30,7 @@ import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.testFramework.Timings;
import com.intellij.util.ThrowableRunnable;
import com.intellij.util.TimeoutUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -320,4 +322,41 @@ public class ApplicationImplTest extends PlatformTestCase {
thread.join();
assertNotNull(exception);
}
public void testRunProcessWithProgressSynchronouslyInReadAction() throws Throwable {
boolean result = ((ApplicationEx)ApplicationManager.getApplication())
.runProcessWithProgressSynchronouslyInReadAction(getProject(), "title", true, "cancel", null, new Runnable() {
@Override
public void run() {
try {
assertFalse(SwingUtilities.isEventDispatchThread());
assertTrue(ApplicationManager.getApplication().isReadAccessAllowed());
}
catch (Throwable e) {
exception = e;
}
}
});
assertTrue(result);
if (exception != null) throw exception;
}
public void testRunProcessWithProgressSynchronouslyInReadActionWithPendingWriteAction() throws Throwable {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(EmptyRunnable.getInstance());
}
});
boolean result = ((ApplicationEx)ApplicationManager.getApplication())
.runProcessWithProgressSynchronouslyInReadAction(getProject(), "title", true, "cancel", null, new Runnable() {
@Override
public void run() {
TimeoutUtil.sleep(10000);
}
});
assertTrue(result);
UIUtil.dispatchAllInvocationEvents();
if (exception != null) throw exception;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,13 +17,18 @@ package com.intellij.util.io;
import com.intellij.ide.IdeBundle;
import org.jetbrains.annotations.NotNull;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.*;
import static org.junit.Assume.assumeThat;
public class HttpRequestsTest {
private final HttpRequests.RequestProcessor<Void> myProcessor = new HttpRequests.RequestProcessor<Void>() {
@@ -35,6 +40,12 @@ public class HttpRequestsTest {
}
};
@Before
public void setUp() throws Exception {
InetAddress addr = InetAddress.getByName("openjdk.java.net");
assumeThat(addr, instanceOf(Inet4Address.class));
}
@Test
public void testLimit() {
try {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -149,6 +149,7 @@ public abstract class BreakpointManagerBase<T extends BreakpointBase<?>> impleme
@NotNull
@Override
public Promise<Void> flush(@NotNull Breakpoint breakpoint) {
//noinspection unchecked
return ((T)breakpoint).flush(this);
}
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
@@ -13,6 +13,8 @@
<orderEntry type="module" module-name="protocol-reader" />
<orderEntry type="library" name="Trove4j" level="project" />
<orderEntry type="module" module-name="annotations" />
<orderEntry type="module" module-name="util-rt" />
<orderEntry type="module" module-name="platform-impl" />
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
</component>
</module>
</module>
@@ -1,17 +0,0 @@
package org.jetbrains.protocolReader;
abstract class BoxableType {
static final BoxableType STRING = new StandaloneType(new NamePath("String"), "writeString");
static final BoxableType ANY_STRING = new StandaloneType(new NamePath("String"), "writeString");
static final BoxableType INT = new StandaloneType(new NamePath("int"), "writeInt");
static final BoxableType LONG = new StandaloneType(new NamePath("long"), "writeLong");
static final BoxableType NUMBER = new StandaloneType(new NamePath("double"), "writeDouble");
static final BoxableType BOOLEAN = new StandaloneType(new NamePath("boolean"), "writeBoolean");
static final BoxableType MAP = new StandaloneType(new NamePath("java.util.Map<String, String>"), "writeMap");
abstract CharSequence getFullText();
abstract String getShortText(NamePath contextNamespace);
abstract String getWriteMethodName();
}
@@ -0,0 +1,20 @@
package org.jetbrains.protocolReader
abstract class BoxableType {
abstract fun getFullText(): CharSequence
abstract fun getShortText(contextNamespace: NamePath): String
abstract fun getWriteMethodName(): String
default object {
val STRING: BoxableType = StandaloneType(NamePath("String"), "writeString")
val ANY_STRING: BoxableType = StandaloneType(NamePath("String"), "writeString")
val INT: BoxableType = StandaloneType(NamePath("int"), "writeInt")
val LONG: BoxableType = StandaloneType(NamePath("long"), "writeLong")
val NUMBER: BoxableType = StandaloneType(NamePath("double"), "writeDouble")
val BOOLEAN: BoxableType = StandaloneType(NamePath("boolean"), "writeBoolean")
val MAP: BoxableType = StandaloneType(NamePath("java.util.Map<String, String>"), "writeMap")
}
}
@@ -1,75 +0,0 @@
package org.jetbrains.protocolReader;
import org.jetbrains.annotations.NotNull;
abstract class ClassNameScheme {
private final String suffix;
private final String rootPackage;
private ClassNameScheme(@NotNull String suffix, String rootPackage) {
this.suffix = suffix;
this.rootPackage = rootPackage;
}
@NotNull
NamePath getFullName(@NotNull String domainName, String baseName) {
return new NamePath(getShortName(baseName), new NamePath(getPackageNameVirtual(domainName)));
}
@NotNull
String getShortName(@NotNull String baseName) {
return baseName.endsWith("Descriptor") ? baseName : new String(getShortNameChars(baseName));
}
private char[] getShortNameChars(@NotNull String baseName) {
char[] name = new char[baseName.length() + suffix.length()];
baseName.getChars(0, baseName.length(), name, 0);
if (!suffix.isEmpty()) {
suffix.getChars(0, suffix.length(), name, baseName.length());
}
if (Character.isLowerCase(name[0])) {
name[0] = Character.toUpperCase(name[0]);
}
if (baseName.endsWith("breakpoint")) {
name[baseName.length() - "breakpoint".length()] = 'B';
}
else if (baseName.endsWith("breakpoints")) {
name[baseName.length() - "breakpoints".length()] = 'B';
}
return name;
}
protected String getPackageNameVirtual(String domainName) {
return getPackageName(rootPackage, domainName);
}
@NotNull
public static String getPackageName(@NotNull String rootPackage, @NotNull String domain) {
if (domain.isEmpty()) {
return rootPackage;
}
return rootPackage + '.' + domain.toLowerCase();
}
static class Input extends ClassNameScheme {
Input(@NotNull String suffix, String rootPackage) {
super(suffix, rootPackage);
}
String getParseMethodName(String domain, String name) {
return "read" + Generator.capitalizeFirstChar(domain) + getShortName(name);
}
}
static class Output extends ClassNameScheme {
Output(String suffix, String rootPackage) {
super(suffix, rootPackage);
}
}
static class Common extends ClassNameScheme {
Common(String suffix, String rootPackage) {
super(suffix, rootPackage);
}
}
}
@@ -0,0 +1,54 @@
package org.jetbrains.protocolReader
abstract class ClassNameScheme private(private val suffix: String, private val rootPackage: String) {
fun getFullName(domainName: String, baseName: String): NamePath {
return NamePath(getShortName(baseName), NamePath(getPackageNameVirtual(domainName)))
}
fun getShortName(baseName: String): String {
return if (baseName.endsWith("Descriptor")) baseName else String(getShortNameChars(baseName))
}
private fun getShortNameChars(baseName: String): CharArray {
val name = CharArray(baseName.length() + suffix.length())
baseName.getChars(0, baseName.length(), name, 0)
if (!suffix.isEmpty()) {
suffix.getChars(0, suffix.length(), name, baseName.length())
}
if (Character.isLowerCase(name[0])) {
name[0] = Character.toUpperCase(name[0])
}
if (baseName.endsWith("breakpoint")) {
name[baseName.length() - "breakpoint".length()] = 'B'
}
else if (baseName.endsWith("breakpoints")) {
name[baseName.length() - "breakpoints".length()] = 'B'
}
return name
}
fun getPackageNameVirtual(domainName: String): String {
return getPackageName(rootPackage, domainName)
}
class Input(suffix: String, rootPackage: String) : ClassNameScheme(suffix, rootPackage) {
fun getParseMethodName(domain: String, name: String): String {
return "read" + Generator.capitalizeFirstChar(domain) + getShortName(name)
}
}
class Output(suffix: String, rootPackage: String) : ClassNameScheme(suffix, rootPackage)
class Common(suffix: String, rootPackage: String) : ClassNameScheme(suffix, rootPackage)
default object {
public fun getPackageName(rootPackage: String, domain: String): String {
if (domain.isEmpty()) {
return rootPackage
}
return rootPackage + '.' + domain.toLowerCase()
}
}
}
@@ -1,48 +0,0 @@
package org.jetbrains.protocolReader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jsonProtocol.ItemDescriptor;
import java.util.ArrayList;
import java.util.List;
abstract class ClassScope {
private final List<TextOutConsumer> additionalMemberTexts = new ArrayList<>(2);
private final NamePath contextNamespace;
final DomainGenerator generator;
ClassScope(@NotNull DomainGenerator generator, @NotNull NamePath classNamespace) {
contextNamespace = classNamespace;
this.generator = generator;
}
protected String getShortClassName() {
return contextNamespace.getLastComponent();
}
NamePath getClassContextNamespace() {
return contextNamespace;
}
void addMember(@NotNull TextOutConsumer out) {
additionalMemberTexts.add(out);
}
void writeAdditionalMembers(@NotNull TextOutput out) {
if (additionalMemberTexts.isEmpty()) {
return;
}
out.newLine();
for (TextOutConsumer deferredWriter : additionalMemberTexts) {
deferredWriter.append(out);
}
}
protected abstract TypeData.Direction getTypeDirection();
@NotNull
protected static String getName(@NotNull ItemDescriptor.Named named) {
return named.shortName() == null ? named.name() : named.shortName();
}
}
@@ -0,0 +1,30 @@
package org.jetbrains.protocolReader
abstract class ClassScope(val generator: DomainGenerator, val classContextNamespace: NamePath) {
private val additionalMemberTexts = ArrayList<TextOutConsumer>(2)
protected fun getShortClassName(): String {
return classContextNamespace.lastComponent
}
fun addMember(out: TextOutConsumer) {
additionalMemberTexts.add(out)
}
fun writeAdditionalMembers(out: TextOutput) {
if (additionalMemberTexts.isEmpty()) {
return
}
out.newLine()
for (deferredWriter in additionalMemberTexts) {
deferredWriter.append(out)
}
}
abstract fun getTypeDirection(): TypeData.Direction
default object {
fun getName(named: ItemDescriptor.Named) = named.shortName() ?: named.name()
}
}
@@ -1,54 +0,0 @@
package org.jetbrains.protocolReader;
import org.jetbrains.jsonProtocol.ProtocolMetaModel;
abstract class CreateStandaloneTypeBindingVisitorBase implements TypeVisitor<StandaloneTypeBinding> {
private final ProtocolMetaModel.StandaloneType type;
private final DomainGenerator generator;
CreateStandaloneTypeBindingVisitorBase(DomainGenerator generator, ProtocolMetaModel.StandaloneType type) {
this.generator = generator;
this.type = type;
}
protected ProtocolMetaModel.StandaloneType getType() {
return type;
}
@Override
public StandaloneTypeBinding visitString() {
return generator.createTypedefTypeBinding(type, StandaloneTypeBinding.PredefinedTarget.STRING, generator.generator.naming.commonTypedef, null);
}
@Override
public StandaloneTypeBinding visitInteger() {
return generator.createTypedefTypeBinding(type, StandaloneTypeBinding.PredefinedTarget.INT, generator.generator.naming.commonTypedef, null);
}
@Override
public StandaloneTypeBinding visitRef(String refName) {
throw new RuntimeException();
}
@Override
public StandaloneTypeBinding visitBoolean() {
throw new RuntimeException();
}
@Override
public StandaloneTypeBinding visitNumber() {
return generator.createTypedefTypeBinding(type, StandaloneTypeBinding.PredefinedTarget.NUMBER,
generator.generator.naming.commonTypedef, null);
}
@Override
public StandaloneTypeBinding visitMap() {
return generator.createTypedefTypeBinding(type, StandaloneTypeBinding.PredefinedTarget.MAP,
generator.generator.naming.commonTypedef, null);
}
@Override
public StandaloneTypeBinding visitUnknown() {
throw new RuntimeException();
}
}
@@ -0,0 +1,32 @@
package org.jetbrains.protocolReader
abstract class CreateStandaloneTypeBindingVisitorBase(private val generator: DomainGenerator, protected val type: ProtocolMetaModel.StandaloneType) : TypeVisitor<StandaloneTypeBinding> {
override fun visitString(): StandaloneTypeBinding {
return generator.createTypedefTypeBinding(type, StandaloneTypeBinding.PredefinedTarget.STRING, generator.generator.naming.commonTypedef, null)
}
override fun visitInteger(): StandaloneTypeBinding {
return generator.createTypedefTypeBinding(type, StandaloneTypeBinding.PredefinedTarget.INT, generator.generator.naming.commonTypedef, null)
}
override fun visitRef(refName: String): StandaloneTypeBinding {
throw RuntimeException()
}
override fun visitBoolean(): StandaloneTypeBinding {
throw RuntimeException()
}
override fun visitNumber(): StandaloneTypeBinding {
return generator.createTypedefTypeBinding(type, StandaloneTypeBinding.PredefinedTarget.NUMBER, generator.generator.naming.commonTypedef, null)
}
override fun visitMap(): StandaloneTypeBinding {
return generator.createTypedefTypeBinding(type, StandaloneTypeBinding.PredefinedTarget.MAP, generator.generator.naming.commonTypedef, null)
}
override fun visitUnknown(): StandaloneTypeBinding {
throw RuntimeException()
}
}
@@ -1,394 +0,0 @@
package org.jetbrains.protocolReader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jsonProtocol.ItemDescriptor;
import org.jetbrains.jsonProtocol.ProtocolMetaModel;
import java.io.IOException;
import java.util.List;
class DomainGenerator {
final ProtocolMetaModel.Domain domain;
final Generator generator;
DomainGenerator(Generator generator, ProtocolMetaModel.Domain domain) {
this.generator = generator;
this.domain = domain;
}
void registerTypes() {
if (domain.types() != null) {
for (ProtocolMetaModel.StandaloneType type : domain.types()) {
generator.typeMap.getTypeData(domain.domain(), type.id()).setType(type);
}
}
}
@NotNull
static String fixMethodName(@NotNull String name) {
int i = name.indexOf("breakpoint");
return i > 0 ? name.substring(0, i) + 'B' + name.substring(i + 1) : name;
}
void generateCommandsAndEvents() throws IOException {
FileUpdater requestsFileUpdater = generator.startJavaFile(generator.naming.params.getPackageNameVirtual(domain.domain()), "Requests.java");
TextOutput out = requestsFileUpdater.out;
out.append("import org.jetbrains.annotations.NotNull;").newLine();
out.append("import org.jetbrains.jsonProtocol.Request;").newLine();
out.newLine().append("public final class ").append("Requests");
out.openBlock();
boolean isFirst = true;
for (ProtocolMetaModel.Command command : domain.commands()) {
boolean hasResponse = command.returns() != null;
boolean onlyMandatoryParams = true;
List<ProtocolMetaModel.Parameter> params = command.parameters();
boolean hasParams = params != null && !params.isEmpty();
if (hasParams) {
for (ProtocolMetaModel.Parameter parameter : params) {
if (parameter.optional()) {
onlyMandatoryParams = false;
}
}
}
String returnType = hasResponse ? generator.naming.commandResult.getShortName(command.name()) : "Void";
if (onlyMandatoryParams) {
if (isFirst) {
isFirst = false;
}
else {
out.newLine().newLine();
}
out.append("@NotNull").newLine().append("public static Request<");
out.append(returnType);
out.append(">").space().append(fixMethodName(command.name())).append("(");
OutputClassScope classScope = new OutputClassScope(this, generator.naming.params.getFullName(domain.domain(), command.name()));
BoxableType[] parameterTypes = hasParams ? new BoxableType[params.size()] : null;
if (hasParams) {
classScope.writeMethodParameters(out, params, parameterTypes);
}
out.append(')').openBlock();
if (hasParams) {
out.append("V8SimpleRequest<").append(returnType).append(">").append(" r =");
}
else {
out.append("return");
}
out.append(" new V8SimpleRequest<").append(returnType).append(">(\"");
if (!domain.domain().isEmpty()) {
out.append(domain.domain()).append('.');
}
out.append(command.name()).append("\")").semi();
if (hasParams) {
classScope.writeWriteCalls(out, params, parameterTypes, "r");
out.newLine().append("return r").semi();
}
out.closeBlock();
}
else {
generateRequest(command, returnType);
}
if (hasResponse) {
FileUpdater fileUpdater = generator.startJavaFile(generator.naming.commandResult, domain, command.name());
generateJsonProtocolInterface(fileUpdater.out, generator.naming.commandResult.getShortName(command.name()), command.description(), command.returns(), null);
fileUpdater.update();
generator.jsonProtocolParserClassNames.add(generator.naming.commandResult.getFullName(domain.domain(), command.name()).getFullText());
generator.parserRootInterfaceItems.add(new ParserRootInterfaceItem(domain.domain(), command.name(), generator.naming.commandResult));
}
}
out.closeBlock();
requestsFileUpdater.update();
if (domain.events() != null) {
for (ProtocolMetaModel.Event event : domain.events()) {
generateEvenData(event);
generator.jsonProtocolParserClassNames.add(generator.naming.eventData.getFullName(domain.domain(), event.name()).getFullText());
generator.parserRootInterfaceItems.add(new ParserRootInterfaceItem(domain.domain(), event.name(), generator.naming.eventData));
}
}
}
private void generateRequest(@NotNull final ProtocolMetaModel.Command command, @NotNull final String returnType) throws IOException {
TextOutConsumer baseTypeBuilder = new TextOutConsumer() {
@Override
public void append(TextOutput out) {
out.space().append("extends ").append(generator.naming.requestClassName).append('<').append(returnType).append('>');
}
};
TextOutConsumer memberBuilder = new TextOutConsumer() {
@Override
public void append(TextOutput out) {
out.append("@NotNull").newLine().append("@Override").newLine().append("public String getMethodName()").openBlock();
out.append("return \"");
if (!domain.domain().isEmpty()) {
out.append(domain.domain()).append('.');
}
out.append(command.name()).append("\";").closeBlock();
}
};
generateTopLevelOutputClass(generator.naming.params, command.name(), command.description(), baseTypeBuilder,
memberBuilder, command.parameters());
}
void generateCommandAdditionalParam(ProtocolMetaModel.StandaloneType type) throws IOException {
generateTopLevelOutputClass(generator.naming.additionalParam, type.id(), type.description(), null, null, type.properties());
}
private <P extends ItemDescriptor.Named> void generateTopLevelOutputClass(@NotNull ClassNameScheme nameScheme,
String baseName,
String description,
@Nullable TextOutConsumer baseType,
@Nullable TextOutConsumer additionalMemberText,
List<P> properties) throws IOException {
FileUpdater fileUpdater = generator.startJavaFile(nameScheme, domain, baseName);
if (nameScheme == generator.naming.params) {
fileUpdater.out.append("import org.jetbrains.annotations.NotNull;").newLine().newLine();
}
generateOutputClass(fileUpdater.out, nameScheme.getFullName(domain.domain(), baseName), description, baseType, additionalMemberText, properties);
fileUpdater.update();
}
private <P extends ItemDescriptor.Named> void generateOutputClass(@NotNull TextOutput out,
NamePath classNamePath,
String description,
@Nullable TextOutConsumer baseType,
TextOutConsumer additionalMemberText,
List<P> properties) {
out.doc(description);
out.append("public final class ").append(classNamePath.getLastComponent());
if (baseType == null) {
out.append(" extends ").append("org.jetbrains.jsonProtocol.OutMessage");
}
else {
baseType.append(out);
}
OutputClassScope classScope = new OutputClassScope(this, classNamePath);
if (additionalMemberText != null) {
classScope.addMember(additionalMemberText);
}
out.openBlock();
classScope.generate(out, properties);
classScope.writeAdditionalMembers(out);
out.closeBlock();
}
StandaloneTypeBinding createStandaloneOutputTypeBinding(@NotNull ProtocolMetaModel.StandaloneType type, @NotNull String name) {
return Generator.switchByType(type, new MyCreateStandaloneTypeBindingVisitorBase(this, type, name));
}
StandaloneTypeBinding createStandaloneInputTypeBinding(ProtocolMetaModel.StandaloneType type) {
return Generator.switchByType(type, new CreateStandaloneTypeBindingVisitorBase(this, type) {
@Override
public StandaloneTypeBinding visitObject(List<ProtocolMetaModel.ObjectProperty> properties) {
return createStandaloneObjectInputTypeBinding(getType(), properties);
}
@Override
public StandaloneTypeBinding visitEnum(List<String> enumConstants) {
return createStandaloneEnumInputTypeBinding(getType(), enumConstants,
TypeData.Direction.INPUT);
}
@Override
public StandaloneTypeBinding visitArray(ProtocolMetaModel.ArrayItemType items) {
ResolveAndGenerateScope resolveAndGenerateScope = new ResolveAndGenerateScope() {
// This class is responsible for generating ad hoc type.
// If we ever are to do it, we should generate into string buffer and put strings
// inside TypeDef class.
@Override
public String getDomainName() {
return domain.domain();
}
@Override
public TypeData.Direction getTypeDirection() {
return TypeData.Direction.INPUT;
}
@Override
public <T extends ItemDescriptor> TypeDescriptor resolveType(T typedObject) {
throw new UnsupportedOperationException();
}
@Override
public BoxableType generateNestedObject(String description, List<ProtocolMetaModel.ObjectProperty> properties) {
throw new UnsupportedOperationException();
}
};
BoxableType itemBoxableType = generator.resolveType(items, resolveAndGenerateScope).getType();
final BoxableType arrayType = new ListType(itemBoxableType);
StandaloneTypeBinding.Target target = new StandaloneTypeBinding.Target() {
@Override
public BoxableType resolve(ResolveContext context) {
return arrayType;
}
};
return createTypedefTypeBinding(getType(), target, generator.naming.inputTypedef, TypeData.Direction.INPUT);
}
});
}
StandaloneTypeBinding createStandaloneObjectInputTypeBinding(@NotNull final ProtocolMetaModel.StandaloneType type, @Nullable final List<ProtocolMetaModel.ObjectProperty> properties) {
final String name = type.id();
final NamePath fullTypeName = generator.naming.inputValue.getFullName(domain.domain(), name);
generator.jsonProtocolParserClassNames.add(fullTypeName.getFullText());
return new StandaloneTypeBinding() {
@Override
public BoxableType getJavaType() {
return new StandaloneType(fullTypeName, "writeMessage");
}
@Override
public void generate() throws IOException {
NamePath className = generator.naming.inputValue.getFullName(domain.domain(), name);
FileUpdater fileUpdater = generator.startJavaFile(generator.naming.inputValue, domain, name);
TextOutput out = fileUpdater.out;
if (type.description() != null) {
out.doc(type.description());
}
out.append("@org.jetbrains.jsonProtocol.JsonType").newLine();
out.append("public interface ").append(className.getLastComponent()).openBlock();
InputClassScope classScope = new InputClassScope(DomainGenerator.this, className);
if (properties != null) {
classScope.generateDeclarationBody(out, properties);
}
classScope.writeAdditionalMembers(out);
out.closeBlock();
fileUpdater.update();
}
@Override public TypeData.Direction getDirection() {
return TypeData.Direction.INPUT;
}
};
}
StandaloneTypeBinding createStandaloneEnumInputTypeBinding(final ProtocolMetaModel.StandaloneType type,
final List<String> enumConstants, final TypeData.Direction direction) {
final String name = type.id();
return new StandaloneTypeBinding() {
@Override
public BoxableType getJavaType() {
return new StandaloneType(generator.naming.inputEnum.getFullName(domain.domain(), name), "writeEnum");
}
@Override
public void generate() throws IOException {
FileUpdater fileUpdater = generator.startJavaFile(generator.naming.inputEnum, domain, name);
fileUpdater.out.doc(type.description());
Enums.appendEnums(enumConstants, generator.naming.inputEnum.getShortName(name), true, fileUpdater.out);
fileUpdater.update();
}
@Override
public TypeData.Direction getDirection() {
return direction;
}
};
}
/**
* Typedef is an empty class that just holds description and
* refers to an actual type (such as String).
*/
StandaloneTypeBinding createTypedefTypeBinding(final ProtocolMetaModel.StandaloneType type, StandaloneTypeBinding.Target target,
final ClassNameScheme nameScheme, final TypeData.Direction direction) {
final String name = type.id();
final NamePath typedefJavaName = nameScheme.getFullName(domain.domain(), name);
final BoxableType actualJavaType = target.resolve(new StandaloneTypeBinding.Target.ResolveContext() {
@Override
public BoxableType generateNestedObject(String shortName, String description, List<ProtocolMetaModel.ObjectProperty> properties) {
NamePath classNamePath = new NamePath(shortName, typedefJavaName);
if (direction == null) {
throw new RuntimeException("Unsupported");
}
switch (direction) {
case INPUT:
throw new RuntimeException("TODO");
case OUTPUT:
TextOutput out = new TextOutput(new StringBuilder());
generateOutputClass(out, classNamePath, description, null, null, properties);
break;
default:
throw new RuntimeException();
}
return new StandaloneType(new NamePath(shortName, typedefJavaName), "writeMessage");
}
});
return new StandaloneTypeBinding() {
@Override
public BoxableType getJavaType() {
return actualJavaType;
}
@Override
public void generate() {
}
@Override
public TypeData.Direction getDirection() {
return direction;
}
};
}
private void generateEvenData(final ProtocolMetaModel.Event event) throws IOException {
String className = generator.naming.eventData.getShortName(event.name());
FileUpdater fileUpdater = generator.startJavaFile(generator.naming.eventData, domain, event.name());
final String domainName = domain.domain();
final CharSequence fullName = generator.naming.eventData.getFullName(domainName, event.name()).getFullText();
generateJsonProtocolInterface(fileUpdater.out, className, event.description(), event.parameters(), new TextOutConsumer() {
@Override
public void append(TextOutput out) {
out.newLine().append("org.jetbrains.wip.protocol.WipEventType<").append(fullName).append("> TYPE").newLine();
out.append("\t= new org.jetbrains.wip.protocol.WipEventType<").append(fullName).append(">");
out.append("(\"").append(domainName).append('.').append(event.name()).append("\", ").append(fullName).append(".class)").openBlock();
{
out.append("@Override").newLine().append("public ").append(fullName).append(" read(");
out.append(generator.naming.inputPackage).append('.').append(Generator.READER_INTERFACE_NAME + " protocolReader, ").append(Util.JSON_READER_PARAMETER_DEF).append(")").openBlock();
out.append("return protocolReader.").append(generator.naming.eventData.getParseMethodName(domainName, event.name())).append("(reader);").closeBlock();
}
out.closeBlock();
out.semi();
}
});
fileUpdater.update();
}
private void generateJsonProtocolInterface(TextOutput out, String className, String description, List<ProtocolMetaModel.Parameter> parameters, TextOutConsumer additionalMembersText) {
if (description != null) {
out.doc(description);
}
out.append("@org.jetbrains.jsonProtocol.JsonType").newLine().append("public interface ").append(className).openBlock();
InputClassScope classScope = new InputClassScope(this, new NamePath(className, new NamePath(ClassNameScheme.getPackageName(generator.naming.inputPackage, domain.domain()))));
if (additionalMembersText != null) {
classScope.addMember(additionalMembersText);
}
if (parameters != null) {
classScope.generateDeclarationBody(out, parameters);
}
classScope.writeAdditionalMembers(out);
out.closeBlock();
}
}
@@ -0,0 +1,348 @@
package org.jetbrains.protocolReader
class DomainGenerator(val generator: Generator, val domain: ProtocolMetaModel.Domain) {
fun registerTypes() {
if (domain.types() != null) {
for (type in domain.types()!!) {
generator.typeMap.getTypeData(domain.domain(), type.id()).setType(type)
}
}
}
throws(javaClass<IOException>())
fun generateCommandsAndEvents() {
val requestsFileUpdater = generator.startJavaFile(generator.naming.params.getPackageNameVirtual(domain.domain()), "Requests.java")
val out = requestsFileUpdater.out
out.append("import org.jetbrains.annotations.NotNull;").newLine()
out.append("import org.jetbrains.jsonProtocol.Request;").newLine()
out.newLine().append("public final class ").append("Requests")
out.openBlock()
var isFirst = true
for (command in domain.commands()) {
val hasResponse = command.returns() != null
var onlyMandatoryParams = true
val params = command.parameters()
val hasParams = params != null && !params.isEmpty()
if (hasParams) {
for (parameter in params!!) {
if (parameter.optional()) {
onlyMandatoryParams = false
}
}
}
val returnType = if (hasResponse) generator.naming.commandResult.getShortName(command.name()) else "Void"
if (onlyMandatoryParams) {
if (isFirst) {
isFirst = false
}
else {
out.newLine().newLine()
}
out.append("@NotNull").newLine().append("public static Request<")
out.append(returnType)
out.append(">").space().append(fixMethodName(command.name())).append("(")
val classScope = OutputClassScope(this, generator.naming.params.getFullName(domain.domain(), command.name()))
val parameterTypes = if (hasParams) arrayOfNulls<BoxableType>(params!!.size()) else null
if (hasParams) {
classScope.writeMethodParameters<ProtocolMetaModel.Parameter>(out, params!!, parameterTypes!!)
}
out.append(')').openBlock()
if (hasParams) {
out.append("V8SimpleRequest<").append(returnType).append(">").append(" r =")
}
else {
out.append("return")
}
out.append(" new V8SimpleRequest<").append(returnType).append(">(\"")
if (!domain.domain().isEmpty()) {
out.append(domain.domain()).append('.')
}
out.append(command.name()).append("\")").semi()
if (hasParams) {
classScope.writeWriteCalls<ProtocolMetaModel.Parameter>(out, params!!, parameterTypes!!, "r")
out.newLine().append("return r").semi()
}
out.closeBlock()
}
else {
generateRequest(command, returnType)
}
if (hasResponse) {
val fileUpdater = generator.startJavaFile(generator.naming.commandResult, domain, command.name())
generateJsonProtocolInterface(fileUpdater.out, generator.naming.commandResult.getShortName(command.name()), command.description(), command.returns(), null)
fileUpdater.update()
generator.jsonProtocolParserClassNames.add(generator.naming.commandResult.getFullName(domain.domain(), command.name()).getFullText())
generator.parserRootInterfaceItems.add(ParserRootInterfaceItem(domain.domain(), command.name(), generator.naming.commandResult))
}
}
out.closeBlock()
requestsFileUpdater.update()
if (domain.events() != null) {
for (event in domain.events()!!) {
generateEvenData(event)
generator.jsonProtocolParserClassNames.add(generator.naming.eventData.getFullName(domain.domain(), event.name()).getFullText())
generator.parserRootInterfaceItems.add(ParserRootInterfaceItem(domain.domain(), event.name(), generator.naming.eventData))
}
}
}
throws(javaClass<IOException>())
private fun generateRequest(command: ProtocolMetaModel.Command, returnType: String) {
val baseTypeBuilder = object : TextOutConsumer {
override fun append(out: TextOutput) {
out.space().append("extends ").append(generator.naming.requestClassName).append('<').append(returnType).append('>')
}
}
val memberBuilder = object : TextOutConsumer {
override fun append(out: TextOutput) {
out.append("@NotNull").newLine().append("@Override").newLine().append("public String getMethodName()").openBlock()
out.append("return \"")
if (!domain.domain().isEmpty()) {
out.append(domain.domain()).append('.')
}
out.append(command.name()).append("\";").closeBlock()
}
}
generateTopLevelOutputClass(generator.naming.params, command.name(), command.description(), baseTypeBuilder, memberBuilder, command.parameters())
}
fun generateCommandAdditionalParam(type: ProtocolMetaModel.StandaloneType) {
generateTopLevelOutputClass(generator.naming.additionalParam, type.id(), type.description(), null, null, type.properties())
}
private fun <P : ItemDescriptor.Named> generateTopLevelOutputClass(nameScheme: ClassNameScheme, baseName: String, description: String?, baseType: TextOutConsumer?, additionalMemberText: TextOutConsumer?, properties: List<P>?) {
val fileUpdater = generator.startJavaFile(nameScheme, domain, baseName)
if (nameScheme == generator.naming.params) {
fileUpdater.out.append("import org.jetbrains.annotations.NotNull;").newLine().newLine()
}
generateOutputClass(fileUpdater.out, nameScheme.getFullName(domain.domain(), baseName), description, baseType, additionalMemberText, properties)
fileUpdater.update()
}
private fun <P : ItemDescriptor.Named> generateOutputClass(out: TextOutput, classNamePath: NamePath, description: String?, baseType: TextOutConsumer?, additionalMemberText: TextOutConsumer?, properties: List<P>?) {
out.doc(description)
out.append("public final class ").append(classNamePath.lastComponent)
if (baseType == null) {
out.append(" extends ").append("org.jetbrains.jsonProtocol.OutMessage")
}
else {
baseType.append(out)
}
val classScope = OutputClassScope(this, classNamePath)
if (additionalMemberText != null) {
classScope.addMember(additionalMemberText)
}
out.openBlock()
classScope.generate<P>(out, properties)
classScope.writeAdditionalMembers(out)
out.closeBlock()
}
fun createStandaloneOutputTypeBinding(type: ProtocolMetaModel.StandaloneType, name: String): StandaloneTypeBinding {
return Generator.switchByType<StandaloneTypeBinding>(type, MyCreateStandaloneTypeBindingVisitorBase(this, type, name))
}
fun createStandaloneInputTypeBinding(type: ProtocolMetaModel.StandaloneType): StandaloneTypeBinding {
return Generator.switchByType<StandaloneTypeBinding>(type, object : CreateStandaloneTypeBindingVisitorBase(this, type) {
override fun visitObject(properties: List<ProtocolMetaModel.ObjectProperty>?): StandaloneTypeBinding {
return createStandaloneObjectInputTypeBinding(type, properties)
}
override fun visitEnum(enumConstants: List<String>): StandaloneTypeBinding {
return createStandaloneEnumInputTypeBinding(type, enumConstants, TypeData.Direction.INPUT)
}
override fun visitArray(items: ProtocolMetaModel.ArrayItemType): StandaloneTypeBinding {
val resolveAndGenerateScope = object : ResolveAndGenerateScope {
// This class is responsible for generating ad hoc type.
// If we ever are to do it, we should generate into string buffer and put strings
// inside TypeDef class.
override fun getDomainName(): String {
return domain.domain()
}
override fun getTypeDirection(): TypeData.Direction {
return TypeData.Direction.INPUT
}
override fun <T : ItemDescriptor> resolveType(typedObject: T): TypeDescriptor {
throw UnsupportedOperationException()
}
override fun generateNestedObject(description: String?, properties: List<ProtocolMetaModel.ObjectProperty>?) = throw UnsupportedOperationException()
}
val itemBoxableType = generator.resolveType(items, resolveAndGenerateScope).type
val arrayType = ListType(itemBoxableType)
val target = object : StandaloneTypeBinding.Target {
override fun resolve(context: StandaloneTypeBinding.Target.ResolveContext): BoxableType {
return arrayType
}
}
return createTypedefTypeBinding(type, target, generator.naming.inputTypedef, TypeData.Direction.INPUT)
}
})
}
fun createStandaloneObjectInputTypeBinding(type: ProtocolMetaModel.StandaloneType, properties: List<ProtocolMetaModel.ObjectProperty>?): StandaloneTypeBinding {
val name = type.id()
val fullTypeName = generator.naming.inputValue.getFullName(domain.domain(), name)
generator.jsonProtocolParserClassNames.add(fullTypeName.getFullText())
return object : StandaloneTypeBinding {
override fun getJavaType(): BoxableType {
return StandaloneType(fullTypeName, "writeMessage")
}
throws(javaClass<IOException>())
override fun generate() {
val className = generator.naming.inputValue.getFullName(domain.domain(), name)
val fileUpdater = generator.startJavaFile(generator.naming.inputValue, domain, name)
val out = fileUpdater.out
if (type.description() != null) {
out.doc(type.description())
}
out.append("@org.jetbrains.jsonProtocol.JsonType").newLine()
out.append("public interface ").append(className.lastComponent).openBlock()
val classScope = InputClassScope(this@DomainGenerator, className)
if (properties != null) {
classScope.generateDeclarationBody(out, properties)
}
classScope.writeAdditionalMembers(out)
out.closeBlock()
fileUpdater.update()
}
override fun getDirection(): TypeData.Direction? {
return TypeData.Direction.INPUT
}
}
}
fun createStandaloneEnumInputTypeBinding(type: ProtocolMetaModel.StandaloneType, enumConstants: List<String>, direction: TypeData.Direction): StandaloneTypeBinding {
val name = type.id()
return object : StandaloneTypeBinding {
override fun getJavaType(): BoxableType {
return StandaloneType(generator.naming.inputEnum.getFullName(domain.domain(), name), "writeEnum")
}
throws(javaClass<IOException>())
override fun generate() {
val fileUpdater = generator.startJavaFile(generator.naming.inputEnum, domain, name)
fileUpdater.out.doc(type.description())
Enums.appendEnums(enumConstants, generator.naming.inputEnum.getShortName(name), true, fileUpdater.out)
fileUpdater.update()
}
override fun getDirection(): TypeData.Direction? {
return direction
}
}
}
/**
* Typedef is an empty class that just holds description and
* refers to an actual type (such as String).
*/
fun createTypedefTypeBinding(type: ProtocolMetaModel.StandaloneType, target: StandaloneTypeBinding.Target, nameScheme: ClassNameScheme, direction: TypeData.Direction?): StandaloneTypeBinding {
val name = type.id()
val typedefJavaName = nameScheme.getFullName(domain.domain(), name)
val actualJavaType = target.resolve(object : StandaloneTypeBinding.Target.ResolveContext {
override fun generateNestedObject(shortName: String, description: String?, properties: List<ProtocolMetaModel.ObjectProperty>?): BoxableType {
val classNamePath = NamePath(shortName, typedefJavaName)
if (direction == null) {
throw RuntimeException("Unsupported")
}
when (direction) {
TypeData.Direction.INPUT -> throw RuntimeException("TODO")
TypeData.Direction.OUTPUT -> {
val out = TextOutput(StringBuilder())
generateOutputClass(out, classNamePath, description, null, null, properties)
}
else -> throw RuntimeException()
}
return StandaloneType(NamePath(shortName, typedefJavaName), "writeMessage")
}
})
return object : StandaloneTypeBinding {
override fun getJavaType(): BoxableType {
return actualJavaType
}
override fun generate() {
}
override fun getDirection(): TypeData.Direction? {
return direction
}
}
}
throws(javaClass<IOException>())
private fun generateEvenData(event: ProtocolMetaModel.Event) {
val className = generator.naming.eventData.getShortName(event.name())
val fileUpdater = generator.startJavaFile(generator.naming.eventData, domain, event.name())
val domainName = domain.domain()
val fullName = generator.naming.eventData.getFullName(domainName, event.name()).getFullText()
generateJsonProtocolInterface(fileUpdater.out, className, event.description(), event.parameters(), object : TextOutConsumer {
override fun append(out: TextOutput) {
out.newLine().append("org.jetbrains.wip.protocol.WipEventType<").append(fullName).append("> TYPE").newLine()
out.append("\t= new org.jetbrains.wip.protocol.WipEventType<").append(fullName).append(">")
out.append("(\"").append(domainName).append('.').append(event.name()).append("\", ").append(fullName).append(".class)").openBlock()
run {
out.append("@Override").newLine().append("public ").append(fullName).append(" read(")
out.append(generator.naming.inputPackage).append('.').append(Generator.READER_INTERFACE_NAME + " protocolReader, ").append(JSON_READER_PARAMETER_DEF).append(")").openBlock()
out.append("return protocolReader.").append(generator.naming.eventData.getParseMethodName(domainName, event.name())).append("(reader);").closeBlock()
}
out.closeBlock()
out.semi()
}
})
fileUpdater.update()
}
private fun generateJsonProtocolInterface(out: TextOutput, className: String, description: String?, parameters: List<ProtocolMetaModel.Parameter>?, additionalMembersText: TextOutConsumer?) {
if (description != null) {
out.doc(description)
}
out.append("@org.jetbrains.jsonProtocol.JsonType").newLine().append("public interface ").append(className).openBlock()
val classScope = InputClassScope(this, NamePath(className, NamePath(ClassNameScheme.getPackageName(generator.naming.inputPackage, domain.domain()))))
if (additionalMembersText != null) {
classScope.addMember(additionalMembersText)
}
if (parameters != null) {
classScope.generateDeclarationBody(out, parameters)
}
classScope.writeAdditionalMembers(out)
out.closeBlock()
}
default object {
fun fixMethodName(name: String): String {
val i = name.indexOf("breakpoint")
return if (i > 0) name.substring(0, i) + 'B' + name.substring(i + 1) else name
}
}
}
@@ -1,66 +0,0 @@
package org.jetbrains.protocolReader;
import gnu.trove.THashSet;
import gnu.trove.TObjectProcedure;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
/**
* Records a list of files in the root directory and deletes files that were not re-generated.
*/
class FileSet {
private final Path rootDir;
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private final THashSet<Path> unusedFiles;
FileSet(Path rootDir) throws IOException {
this.rootDir = rootDir;
unusedFiles = new THashSet<Path>();
Files.walkFileTree(rootDir, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
return Files.isHidden(dir) ? FileVisitResult.SKIP_SUBTREE : FileVisitResult.CONTINUE;
}
@NotNull
@Override
public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
if (!Files.isHidden(path)) {
unusedFiles.add(path);
}
return FileVisitResult.CONTINUE;
}
});
}
FileUpdater createFileUpdater(String filePath) {
Path file = rootDir.resolve(filePath);
unusedFiles.remove(file);
return new FileUpdater(file);
}
void deleteOtherFiles() {
unusedFiles.forEach(new TObjectProcedure<Path>() {
@Override
public boolean execute(Path path) {
try {
if (Files.deleteIfExists(path)) {
Path parent = path.getParent();
try (DirectoryStream<Path> stream = Files.newDirectoryStream(parent)) {
if (!stream.iterator().hasNext()) {
Files.delete(parent);
}
}
}
}
catch (IOException e) {
throw new RuntimeException(e);
}
return true;
}
});
}
}
@@ -0,0 +1,56 @@
package org.jetbrains.protocolReader
/**
* Records a list of files in the root directory and deletes files that were not re-generated.
*/
class FileSet [throws(javaClass<IOException>())]
(private val rootDir: Path) {
SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private val unusedFiles: THashSet<Path>
{
unusedFiles = THashSet<Path>()
Files.walkFileTree(rootDir, object : SimpleFileVisitor<Path>() {
throws(javaClass<IOException>())
override fun preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult {
return if (Files.isHidden(dir)) FileVisitResult.SKIP_SUBTREE else FileVisitResult.CONTINUE
}
throws(javaClass<IOException>())
override fun visitFile(path: Path, attrs: BasicFileAttributes): FileVisitResult {
if (!Files.isHidden(path)) {
unusedFiles.add(path)
}
return FileVisitResult.CONTINUE
}
})
}
fun createFileUpdater(filePath: String): FileUpdater {
val file = rootDir.resolve(filePath)
unusedFiles.remove(file)
return FileUpdater(file)
}
fun deleteOtherFiles() {
unusedFiles.forEach(object : TObjectProcedure<Path> {
override fun execute(path: Path): Boolean {
try {
if (Files.deleteIfExists(path)) {
val parent = path.getParent()
Files.newDirectoryStream(parent).use { stream ->
if (!stream.iterator().hasNext()) {
Files.delete(parent)
}
}
}
}
catch (e: IOException) {
throw RuntimeException(e)
}
return true
}
})
}
}
@@ -1,314 +0,0 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.jetbrains.protocolReader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jsonProtocol.ItemDescriptor;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.util.*;
import static org.jetbrains.jsonProtocol.ProtocolMetaModel.*;
/**
* Read metamodel and generates set of files with Java classes/interfaces for the protocol.
*/
class Generator {
private static final String PARSER_INTERFACE_LIST_CLASS_NAME = "GeneratedReaderInterfaceList";
static final String READER_INTERFACE_NAME = "ProtocolResponseReader";
final List<String> jsonProtocolParserClassNames = new ArrayList<>();
final List<ParserRootInterfaceItem> parserRootInterfaceItems = new ArrayList<>();
final TypeMap typeMap = new TypeMap();
private final FileSet fileSet;
final Naming naming;
Generator(String outputDir, String rootPackage, String requestClassName) throws IOException {
fileSet = new FileSet(FileSystems.getDefault().getPath(outputDir));
naming = new Naming(rootPackage, requestClassName);
}
public static final class Naming {
public final ClassNameScheme params;
public final ClassNameScheme additionalParam;
public final ClassNameScheme outputTypedef;
public final ClassNameScheme.Input commandResult;
public final ClassNameScheme.Input eventData;
public final ClassNameScheme inputValue;
public final ClassNameScheme inputEnum;
public final ClassNameScheme inputTypedef;
public final ClassNameScheme commonTypedef;
public final String inputPackage;
public final String requestClassName;
private Naming(String rootPackage, String requestClassName) {
this.requestClassName = requestClassName;
params = new ClassNameScheme.Output("", rootPackage);
additionalParam = new ClassNameScheme.Output("", rootPackage);
outputTypedef = new ClassNameScheme.Output("Typedef", rootPackage);
commonTypedef = new ClassNameScheme.Common("Typedef", rootPackage);
inputPackage = rootPackage;
commandResult = new ClassNameScheme.Input("Result", inputPackage);
eventData = new ClassNameScheme.Input("EventData", inputPackage);
inputValue = new ClassNameScheme.Input("Value", inputPackage);
inputEnum = new ClassNameScheme.Input("", inputPackage);
inputTypedef = new ClassNameScheme.Input("Typedef", inputPackage);
}
}
private static boolean isDomainSkipped(Domain domain) {
if (domain.domain().equals("CSS") || domain.domain().equals("Inspector")) {
return false;
}
// todo DOMDebugger
return domain.hidden() ||
domain.domain().equals("DOMDebugger") ||
domain.domain().equals("Timeline") ||
domain.domain().equals("Input");
}
void go(Root metamodel) throws IOException {
initializeKnownTypes();
List<Domain> domainList = metamodel.domains();
Map<String, DomainGenerator> domainGeneratorMap = new HashMap<>();
for (Domain domain : domainList) {
if (isDomainSkipped(domain)) {
System.out.println("Domain skipped: " + domain.domain());
continue;
}
DomainGenerator domainGenerator = new DomainGenerator(this, domain);
domainGeneratorMap.put(domain.domain(), domainGenerator);
domainGenerator.registerTypes();
}
for (Domain domain : domainList) {
if (!isDomainSkipped(domain)) {
System.out.println("Domain generated: " + domain.domain());
}
}
typeMap.setDomainGeneratorMap(domainGeneratorMap);
for (DomainGenerator domainGenerator : domainGeneratorMap.values()) {
domainGenerator.generateCommandsAndEvents();
}
typeMap.generateRequestedTypes();
generateParserInterfaceList();
generateParserRoot(parserRootInterfaceItems);
fileSet.deleteOtherFiles();
}
TypeDescriptor resolveType(@NotNull final ItemDescriptor typedObject, @NotNull final ResolveAndGenerateScope scope) {
final boolean optional = typedObject instanceof ItemDescriptor.Named && ((ItemDescriptor.Named)typedObject).optional();
return switchByType(typedObject, new TypeVisitor<TypeDescriptor>() {
@Override
public TypeDescriptor visitRef(String refName) {
return new TypeDescriptor(resolveRefType(scope.getDomainName(), refName, scope.getTypeDirection()), optional);
}
@Override
public TypeDescriptor visitBoolean() {
return new TypeDescriptor(BoxableType.BOOLEAN, optional);
}
@Override
public TypeDescriptor visitEnum(List<String> enumConstants) {
assert scope instanceof MemberScope;
return new TypeDescriptor(((MemberScope)scope).generateEnum(typedObject.description(), enumConstants), optional);
}
@Override
public TypeDescriptor visitString() {
return new TypeDescriptor(BoxableType.STRING, optional);
}
@Override
public TypeDescriptor visitInteger() {
return new TypeDescriptor(BoxableType.INT, optional);
}
@Override
public TypeDescriptor visitNumber() {
return new TypeDescriptor(BoxableType.NUMBER, optional);
}
@Override
public TypeDescriptor visitMap() {
return new TypeDescriptor(BoxableType.MAP, optional);
}
@Override
public TypeDescriptor visitArray(ArrayItemType items) {
BoxableType type = scope.resolveType(items).getType();
return new TypeDescriptor(new ListType(type), optional, false, type == BoxableType.ANY_STRING);
}
@Override
public TypeDescriptor visitObject(List<ObjectProperty> properties) {
return new TypeDescriptor(scope.generateNestedObject(typedObject.description(), properties), optional);
}
@Override
public TypeDescriptor visitUnknown() {
return new TypeDescriptor(BoxableType.STRING, optional, false, true);
}
});
}
private void generateParserInterfaceList() throws IOException {
FileUpdater fileUpdater = startJavaFile(naming.inputPackage, PARSER_INTERFACE_LIST_CLASS_NAME + ".java");
// Write classes in stable order.
Collections.sort(jsonProtocolParserClassNames);
TextOutput out = fileUpdater.out;
out.append("public class ").append(PARSER_INTERFACE_LIST_CLASS_NAME).openBlock();
out.append("public static final Class<?>[] LIST =").openBlock();
for (String name : jsonProtocolParserClassNames) {
out.append(name).append(".class,").newLine();
}
out.closeBlock();
out.semi();
out.closeBlock();
fileUpdater.update();
}
private void generateParserRoot(List<ParserRootInterfaceItem> parserRootInterfaceItems) throws IOException {
FileUpdater fileUpdater = startJavaFile(naming.inputPackage, READER_INTERFACE_NAME + ".java");
// Write classes in stable order.
Collections.sort(parserRootInterfaceItems);
TextOutput out = fileUpdater.out;
out.append("public abstract class ").append(READER_INTERFACE_NAME).space().append("implements org.jetbrains.jsonProtocol.ResponseResultReader").openBlock();
for (ParserRootInterfaceItem item : parserRootInterfaceItems) {
item.writeCode(out);
}
out.newLine().newLine().append("@Override").newLine().append("public Object readResult(String methodName, org.jetbrains.io.JsonReaderEx reader)");
out.openBlock();
boolean isNotFirst = false;
for (ParserRootInterfaceItem item : parserRootInterfaceItems) {
if (isNotFirst) {
out.append("else ");
}
else {
isNotFirst = true;
}
out.append("if (methodName.equals(\"");
if (!item.domain.isEmpty()) {
out.append(item.domain).append('.');
}
out.append(item.name).append('"').append(")) return ");
item.appendReadMethodName(out);
out.append("(reader)").semi().newLine();
}
out.append("else return null").semi();
out.closeBlock();
out.closeBlock();
fileUpdater.update();
}
/**
* Resolve absolute (DOMAIN.TYPE) or relative (TYPE) type name
*/
private BoxableType resolveRefType(String scopeDomainName, String refName,
TypeData.Direction direction) {
int pos = refName.indexOf('.');
String domainName;
String shortName;
if (pos == -1) {
domainName = scopeDomainName;
shortName = refName;
}
else {
domainName = refName.substring(0, pos);
shortName = refName.substring(pos + 1);
}
return typeMap.resolve(domainName, shortName, direction);
}
static String generateMethodNameSubstitute(@NotNull String originalName, @NotNull TextOutput out) {
if (!BAD_METHOD_NAMES.contains(originalName)) {
return originalName;
}
out.append("@org.jetbrains.jsonProtocol.JsonField(jsonLiteralName=\"").append(originalName).append("\")").newLine();
return "get" + Character.toUpperCase(originalName.charAt(0)) + originalName.substring(1);
}
static String capitalizeFirstChar(String s) {
if (!s.isEmpty() && Character.isLowerCase(s.charAt(0))) {
s = Character.toUpperCase(s.charAt(0)) + s.substring(1);
}
return s;
}
FileUpdater startJavaFile(@NotNull ClassNameScheme nameScheme, Domain domain, String baseName) throws IOException {
return startJavaFile(nameScheme.getPackageNameVirtual(domain.domain()), nameScheme.getShortName(baseName) + ".java");
}
public FileUpdater startJavaFile(@NotNull String packageName, @NotNull String filename) {
FileUpdater fileUpdater = fileSet.createFileUpdater(packageName.replace('.', '/') + '/' + filename);
fileUpdater.out.append("// Generated source").newLine().append("package ").append(packageName).semi().newLine().newLine();
return fileUpdater;
}
static <R> R switchByType(@NotNull ItemDescriptor typedObject, @NotNull TypeVisitor<R> visitor) {
String refName = typedObject instanceof ItemDescriptor.Referenceable ? ((ItemDescriptor.Referenceable)typedObject).ref() : null;
if (refName != null) {
return visitor.visitRef(refName);
}
String typeName = typedObject.type();
switch (typeName) {
case BOOLEAN_TYPE:
return visitor.visitBoolean();
case STRING_TYPE:
if (typedObject.getEnum() != null) {
return visitor.visitEnum(typedObject.getEnum());
}
return visitor.visitString();
case INTEGER_TYPE:
case "int":
return visitor.visitInteger();
case NUMBER_TYPE:
return visitor.visitNumber();
case ARRAY_TYPE:
return visitor.visitArray(typedObject.items());
case OBJECT_TYPE:
if (!(typedObject instanceof ItemDescriptor.Type)) {
return visitor.visitObject(null);
}
List<ObjectProperty> properties = ((ItemDescriptor.Type)typedObject).properties();
if (properties == null || properties.isEmpty()) {
return visitor.visitMap();
}
else {
return visitor.visitObject(properties);
}
case ANY_TYPE:
return visitor.visitUnknown();
case UNKNOWN_TYPE:
return visitor.visitUnknown();
}
throw new RuntimeException("Unrecognized type " + typeName);
}
private static void initializeKnownTypes() {
// Code example:
// typeMap.getTypeData("Page", "Cookie").getInput().setJavaTypeName("Object");
}
private static final Set<String> BAD_METHOD_NAMES = new HashSet<>(Collections.singletonList("this"));
}
@@ -0,0 +1,288 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.jetbrains.protocolReader
/**
* Read metamodel and generates set of files with Java classes/interfaces for the protocol.
*/
class Generator [throws(javaClass<IOException>())]
(outputDir: String, rootPackage: String, requestClassName: String) {
val jsonProtocolParserClassNames = ArrayList<String>()
val parserRootInterfaceItems = ArrayList<ParserRootInterfaceItem>()
val typeMap = TypeMap()
private val fileSet: FileSet
val naming: Naming
init {
fileSet = FileSet(FileSystems.getDefault().getPath(outputDir))
naming = Naming(rootPackage, requestClassName)
}
public class Naming(public val inputPackage: String, public val requestClassName: String) {
public val params: ClassNameScheme
public val additionalParam: ClassNameScheme
public val outputTypedef: ClassNameScheme
public val commandResult: ClassNameScheme.Input
public val eventData: ClassNameScheme.Input
public val inputValue: ClassNameScheme
public val inputEnum: ClassNameScheme
public val inputTypedef: ClassNameScheme
public val commonTypedef: ClassNameScheme
init {
params = ClassNameScheme.Output("", inputPackage)
additionalParam = ClassNameScheme.Output("", inputPackage)
outputTypedef = ClassNameScheme.Output("Typedef", inputPackage)
commonTypedef = ClassNameScheme.Common("Typedef", inputPackage)
commandResult = ClassNameScheme.Input("Result", inputPackage)
eventData = ClassNameScheme.Input("EventData", inputPackage)
inputValue = ClassNameScheme.Input("Value", inputPackage)
inputEnum = ClassNameScheme.Input("", inputPackage)
inputTypedef = ClassNameScheme.Input("Typedef", inputPackage)
}
}
throws(javaClass<IOException>())
fun go(metamodel: Root) {
initializeKnownTypes()
val domainList = metamodel.domains()
val domainGeneratorMap = HashMap<String, DomainGenerator>()
for (domain in domainList) {
if (isDomainSkipped(domain)) {
System.out.println("Domain skipped: " + domain.domain())
continue
}
val domainGenerator = DomainGenerator(this, domain)
domainGeneratorMap.put(domain.domain(), domainGenerator)
domainGenerator.registerTypes()
}
for (domain in domainList) {
if (!isDomainSkipped(domain)) {
System.out.println("Domain generated: " + domain.domain())
}
}
typeMap.setDomainGeneratorMap(domainGeneratorMap)
for (domainGenerator in domainGeneratorMap.values()) {
domainGenerator.generateCommandsAndEvents()
}
typeMap.generateRequestedTypes()
generateParserInterfaceList()
generateParserRoot(parserRootInterfaceItems)
fileSet.deleteOtherFiles()
}
fun resolveType(typedObject: ItemDescriptor, scope: ResolveAndGenerateScope): TypeDescriptor {
val optional = typedObject is ItemDescriptor.Named && (typedObject : ItemDescriptor.Named).optional()
return switchByType(typedObject, object : TypeVisitor<TypeDescriptor> {
override fun visitRef(refName: String): TypeDescriptor {
return TypeDescriptor(resolveRefType(scope.getDomainName(), refName, scope.getTypeDirection()), optional)
}
override fun visitBoolean(): TypeDescriptor {
return TypeDescriptor(BoxableType.BOOLEAN, optional)
}
override fun visitEnum(enumConstants: List<String>): TypeDescriptor {
assert(scope is MemberScope)
return TypeDescriptor((scope as MemberScope).generateEnum(typedObject.description(), enumConstants), optional)
}
override fun visitString(): TypeDescriptor {
return TypeDescriptor(BoxableType.STRING, optional)
}
override fun visitInteger(): TypeDescriptor {
return TypeDescriptor(BoxableType.INT, optional)
}
override fun visitNumber(): TypeDescriptor {
return TypeDescriptor(BoxableType.NUMBER, optional)
}
override fun visitMap(): TypeDescriptor {
return TypeDescriptor(BoxableType.MAP, optional)
}
override fun visitArray(items: ArrayItemType): TypeDescriptor {
val type = scope.resolveType<ArrayItemType>(items).type
return TypeDescriptor(ListType(type), optional, false, type == BoxableType.ANY_STRING)
}
override fun visitObject(properties: List<ObjectProperty>?): TypeDescriptor {
return TypeDescriptor(scope.generateNestedObject(typedObject.description(), properties!!), optional)
}
override fun visitUnknown(): TypeDescriptor {
return TypeDescriptor(BoxableType.STRING, optional, false, true)
}
})
}
throws(javaClass<IOException>())
private fun generateParserInterfaceList() {
val fileUpdater = startJavaFile(naming.inputPackage, PARSER_INTERFACE_LIST_CLASS_NAME + ".java")
// Write classes in stable order.
Collections.sort<String>(jsonProtocolParserClassNames)
val out = fileUpdater.out
out.append("public class ").append(PARSER_INTERFACE_LIST_CLASS_NAME).openBlock()
out.append("public static final Class<?>[] LIST =").openBlock()
for (name in jsonProtocolParserClassNames) {
out.append(name).append(".class,").newLine()
}
out.closeBlock()
out.semi()
out.closeBlock()
fileUpdater.update()
}
throws(javaClass<IOException>())
private fun generateParserRoot(parserRootInterfaceItems: List<ParserRootInterfaceItem>) {
val fileUpdater = startJavaFile(naming.inputPackage, READER_INTERFACE_NAME + ".java")
// Write classes in stable order.
Collections.sort<ParserRootInterfaceItem>(parserRootInterfaceItems)
val out = fileUpdater.out
out.append("public abstract class ").append(READER_INTERFACE_NAME).space().append("implements org.jetbrains.jsonProtocol.ResponseResultReader").openBlock()
for (item in parserRootInterfaceItems) {
item.writeCode(out)
}
out.newLine().newLine().append("@Override").newLine().append("public Object readResult(String methodName, org.jetbrains.io.JsonReaderEx reader)")
out.openBlock()
var isNotFirst = false
for (item in parserRootInterfaceItems) {
if (isNotFirst) {
out.append("else ")
}
else {
isNotFirst = true
}
out.append("if (methodName.equals(\"")
if (!item.domain.isEmpty()) {
out.append(item.domain).append('.')
}
out.append(item.name).append('"').append(")) return ")
item.appendReadMethodName(out)
out.append("(reader)").semi().newLine()
}
out.append("else return null").semi()
out.closeBlock()
out.closeBlock()
fileUpdater.update()
}
/**
* Resolve absolute (DOMAIN.TYPE) or relative (TYPE) type name
*/
private fun resolveRefType(scopeDomainName: String, refName: String, direction: TypeData.Direction): BoxableType {
val pos = refName.indexOf('.')
val domainName: String
val shortName: String
if (pos == -1) {
domainName = scopeDomainName
shortName = refName
}
else {
domainName = refName.substring(0, pos)
shortName = refName.substring(pos + 1)
}
return typeMap.resolve(domainName, shortName, direction)!!
}
throws(javaClass<IOException>())
fun startJavaFile(nameScheme: ClassNameScheme, domain: Domain, baseName: String): FileUpdater {
return startJavaFile(nameScheme.getPackageNameVirtual(domain.domain()), nameScheme.getShortName(baseName) + ".java")
}
public fun startJavaFile(packageName: String, filename: String): FileUpdater {
val fileUpdater = fileSet.createFileUpdater(packageName.replace('.', '/') + '/' + filename)
fileUpdater.out.append("// Generated source").newLine().append("package ").append(packageName).semi().newLine().newLine()
return fileUpdater
}
default object {
private val PARSER_INTERFACE_LIST_CLASS_NAME = "GeneratedReaderInterfaceList"
val READER_INTERFACE_NAME = "ProtocolResponseReader"
private fun isDomainSkipped(domain: Domain): Boolean {
if (domain.domain() == "CSS" || domain.domain() == "Inspector") {
return false
}
// todo DOMDebugger
return domain.hidden() || domain.domain() == "DOMDebugger" || domain.domain() == "Timeline" || domain.domain() == "Input"
}
fun generateMethodNameSubstitute(originalName: String, out: TextOutput): String {
if (!BAD_METHOD_NAMES.contains(originalName)) {
return originalName
}
out.append("@org.jetbrains.jsonProtocol.JsonField(jsonLiteralName=\"").append(originalName).append("\")").newLine()
return "get" + Character.toUpperCase(originalName.charAt(0)) + originalName.substring(1)
}
fun capitalizeFirstChar(s: String): String {
if (!s.isEmpty() && Character.isLowerCase(s.charAt(0))) {
return Character.toUpperCase(s.charAt(0)) + s.substring(1)
}
return s
}
fun <R> switchByType(typedObject: ItemDescriptor, visitor: TypeVisitor<R>): R {
val refName = if (typedObject is ItemDescriptor.Referenceable) (typedObject : ItemDescriptor.Referenceable).ref() else null
if (refName != null) {
return visitor.visitRef(refName)
}
val typeName = typedObject.type()
when (typeName) {
ProtocolMetaModel.BOOLEAN_TYPE -> return visitor.visitBoolean()
ProtocolMetaModel.STRING_TYPE -> {
if (typedObject.getEnum() != null) {
return visitor.visitEnum(typedObject.getEnum()!!)
}
return visitor.visitString()
}
ProtocolMetaModel.INTEGER_TYPE, "int" -> return visitor.visitInteger()
ProtocolMetaModel.NUMBER_TYPE -> return visitor.visitNumber()
ProtocolMetaModel.ARRAY_TYPE -> return visitor.visitArray(typedObject.items())
ProtocolMetaModel.OBJECT_TYPE -> {
if (typedObject !is ItemDescriptor.Type) {
return visitor.visitObject(null)
}
val properties = (typedObject : ItemDescriptor.Type).properties()
if (properties == null || properties.isEmpty()) {
return visitor.visitMap()
}
else {
return visitor.visitObject(properties)
}
return visitor.visitUnknown()
}
ProtocolMetaModel.ANY_TYPE -> return visitor.visitUnknown()
ProtocolMetaModel.UNKNOWN_TYPE -> return visitor.visitUnknown()
}
throw RuntimeException("Unrecognized type " + typeName)
}
private fun initializeKnownTypes() {
// Code example:
// typeMap.getTypeData("Page", "Cookie").getInput().setJavaTypeName("Object");
}
private val BAD_METHOD_NAMES = HashSet(listOf("this"))
}
}
@@ -1,86 +0,0 @@
package org.jetbrains.protocolReader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jsonProtocol.ItemDescriptor.Named;
import org.jetbrains.jsonProtocol.ProtocolMetaModel.ObjectProperty;
import java.util.List;
class InputClassScope extends ClassScope {
InputClassScope(DomainGenerator generator, NamePath namePath) {
super(generator, namePath);
}
void generateDeclarationBody(@NotNull TextOutput out, @NotNull List<? extends Named> list) {
for (int i = 0, n = list.size(); i < n; i++) {
Named named = list.get(i);
if (named.description() != null) {
out.doc(named.description());
}
String name = getName(named);
String declarationName = Generator.generateMethodNameSubstitute(name, out);
TypeDescriptor typeDescriptor = new InputMemberScope(name).resolveType(named);
typeDescriptor.writeAnnotations(out);
out.append(typeDescriptor.getType().getShortText(getClassContextNamespace())).space().append(declarationName).append("();");
if (i != (n - 1)) {
out.newLine().newLine();
}
}
}
@Override
protected TypeData.Direction getTypeDirection() {
return TypeData.Direction.INPUT;
}
class InputMemberScope extends MemberScope {
InputMemberScope(String memberName) {
super(InputClassScope.this, memberName);
}
@Override
public BoxableType generateEnum(final String description, final List<String> enumConstants) {
final String enumName = Generator.capitalizeFirstChar(getMemberName());
addMember(new TextOutConsumer() {
@Override
public void append(TextOutput out) {
out.newLine().doc(description);
Enums.appendEnums(enumConstants, enumName, true, out);
}
});
return new StandaloneType(new NamePath(enumName, getClassContextNamespace()), "writeEnum");
}
@Override
public BoxableType generateNestedObject(final String description, final List<ObjectProperty> propertyList) {
final String objectName = Generator.capitalizeFirstChar(getMemberName());
addMember(new TextOutConsumer() {
@Override
public void append(TextOutput out) {
out.newLine().doc(description);
if (propertyList == null) {
out.append("@org.jetbrains.jsonProtocol.JsonType(allowsOtherProperties=true)").newLine();
out.append("public interface ").append(objectName).append(" extends org.jetbrains.jsonProtocol.JsonObjectBased").openBlock();
}
else {
out.append("@org.jetbrains.jsonProtocol.JsonType").newLine();
out.append("public interface ").append(objectName).openBlock();
for (ObjectProperty property : propertyList) {
out.doc(property.description());
String methodName = Generator.generateMethodNameSubstitute(getName(property), out);
MemberScope memberScope = new InputMemberScope(getName(property));
TypeDescriptor propertyTypeData = memberScope.resolveType(property);
propertyTypeData.writeAnnotations(out);
out.append(propertyTypeData.getType().getShortText(getClassContextNamespace()) + ' ' + methodName + "();").newLine();
}
}
out.closeBlock();
}
});
return new StandaloneType(new NamePath(objectName, getClassContextNamespace()), "writeMessage");
}
}
}
@@ -0,0 +1,73 @@
package org.jetbrains.protocolReader
class InputClassScope(generator: DomainGenerator, namePath: NamePath) : ClassScope(generator, namePath) {
fun generateDeclarationBody(out: TextOutput, list: List<Named>) {
run {
var i = 0
val n = list.size()
while (i < n) {
val named = list.get(i)
if (named.description() != null) {
out.doc(named.description())
}
val name = ClassScope.getName(named)
val declarationName = Generator.generateMethodNameSubstitute(name, out)
val typeDescriptor = InputMemberScope(name).resolveType<Named>(named)
typeDescriptor.writeAnnotations(out)
out.append(typeDescriptor.type.getShortText(classContextNamespace)).space().append(declarationName).append("();")
if (i != (n - 1)) {
out.newLine().newLine()
}
i++
}
}
}
override fun getTypeDirection(): TypeData.Direction {
return TypeData.Direction.INPUT
}
inner class InputMemberScope(memberName: String) : MemberScope(this@InputClassScope, memberName) {
override fun generateEnum(description: String?, enumConstants: List<String>): BoxableType {
val enumName = Generator.capitalizeFirstChar(memberName)
addMember(object : TextOutConsumer {
override fun append(out: TextOutput) {
out.newLine().doc(description)
Enums.appendEnums(enumConstants, enumName, true, out)
}
})
return StandaloneType(NamePath(enumName, classContextNamespace), "writeEnum")
}
override fun generateNestedObject(description: String?, properties: List<ObjectProperty>?): BoxableType {
val objectName = Generator.capitalizeFirstChar(memberName)
addMember(object : TextOutConsumer {
override fun append(out: TextOutput) {
out.newLine().doc(description)
if (properties == null) {
out.append("@org.jetbrains.jsonProtocol.JsonType(allowsOtherProperties=true)").newLine()
out.append("public interface ").append(objectName).append(" extends org.jetbrains.jsonProtocol.JsonObjectBased").openBlock()
}
else {
out.append("@org.jetbrains.jsonProtocol.JsonType").newLine()
out.append("public interface ").append(objectName).openBlock()
for (property in properties) {
out.doc(property.description())
val methodName = Generator.generateMethodNameSubstitute(ClassScope.getName(property), out)
val memberScope = InputMemberScope(ClassScope.getName(property))
val propertyTypeData = memberScope.resolveType<ObjectProperty>(property)
propertyTypeData.writeAnnotations(out)
out.append(propertyTypeData.type.getShortText(classContextNamespace) + ' ' + methodName + "();").newLine()
}
}
out.closeBlock()
}
})
return StandaloneType(NamePath(objectName, classContextNamespace), "writeMessage")
}
}
}
@@ -1,44 +0,0 @@
package org.jetbrains.protocolReader;
import org.jetbrains.annotations.NotNull;
class ListType extends BoxableType {
private final BoxableType itemType;
public ListType(@NotNull BoxableType itemType) {
this.itemType = itemType;
}
@Override
String getWriteMethodName() {
if (itemType == STRING) {
return "writeStringList";
}
else if (itemType == LONG) {
return "writeLongArray";
}
else if (itemType == INT) {
return "writeIntArray";
}
else if (itemType == NUMBER) {
return "writeDoubleArray";
}
return "writeList";
}
@Override
String getFullText() {
if (itemType == LONG || itemType == INT || itemType == NUMBER) {
return itemType.getFullText() + "[]";
}
return "java.util.List<" + itemType.getFullText() + '>';
}
@Override
String getShortText(NamePath contextNamespace) {
if (itemType == LONG || itemType == INT || itemType == NUMBER) {
return itemType.getFullText() + "[]";
}
return "java.util.List<" + itemType.getShortText(contextNamespace) + '>';
}
}
@@ -0,0 +1,34 @@
package org.jetbrains.protocolReader
open class ListType(private val itemType: BoxableType) : BoxableType() {
override fun getWriteMethodName(): String {
if (itemType == BoxableType.STRING) {
return "writeStringList"
}
else if (itemType == BoxableType.LONG) {
return "writeLongArray"
}
else if (itemType == BoxableType.INT) {
return "writeIntArray"
}
else if (itemType == BoxableType.NUMBER) {
return "writeDoubleArray"
}
return "writeList"
}
override fun getFullText(): String {
if (itemType == BoxableType.LONG || itemType == BoxableType.INT || itemType == BoxableType.NUMBER) {
return "${itemType.getFullText()}[]"
}
return "java.util.List<" + itemType.getFullText() + '>'
}
override fun getShortText(contextNamespace: NamePath): String {
if (itemType == BoxableType.LONG || itemType == BoxableType.INT || itemType == BoxableType.NUMBER) {
return "${itemType.getFullText()}[]"
}
return "java.util.List<" + itemType.getShortText(contextNamespace) + '>'
}
}
@@ -1,42 +0,0 @@
package org.jetbrains.protocolReader;
import org.jetbrains.jsonProtocol.ItemDescriptor;
import org.jetbrains.jsonProtocol.ProtocolMetaModel;
import java.util.List;
/**
* Member scope is used to generate additional types that are used only from method.
* These types will be named after this method.
*/
abstract class MemberScope implements ResolveAndGenerateScope {
private final String memberName;
private final ClassScope classScope;
MemberScope(ClassScope classScope, String memberName) {
this.classScope = classScope;
this.memberName = memberName;
}
@Override
public <T extends ItemDescriptor> TypeDescriptor resolveType(T typedObject) {
return classScope.generator.generator.resolveType(typedObject, this);
}
protected String getMemberName() {
return memberName;
}
public abstract BoxableType generateEnum(String description, List<String> enumConstants);
public abstract BoxableType generateNestedObject(String description, List<ProtocolMetaModel.ObjectProperty> propertyList);
@Override
public String getDomainName() {
return classScope.generator.domain.domain();
}
@Override
public TypeData.Direction getTypeDirection() {
return classScope.getTypeDirection();
}
}
@@ -0,0 +1,17 @@
package org.jetbrains.protocolReader
/**
* Member scope is used to generate additional types that are used only from method.
* These types will be named after this method.
*/
abstract class MemberScope(private val classScope: ClassScope, protected val memberName: String) : ResolveAndGenerateScope {
override fun <T : ItemDescriptor> resolveType(typedObject: T): TypeDescriptor {
return classScope.generator.generator.resolveType(typedObject, this)
}
public abstract fun generateEnum(description: String?, enumConstants: List<String>): BoxableType
override fun getDomainName() = classScope.generator.domain.domain()
override fun getTypeDirection() = classScope.getTypeDirection()
}
@@ -1,75 +0,0 @@
package org.jetbrains.protocolReader;
import org.jetbrains.jsonProtocol.ItemDescriptor;
import org.jetbrains.jsonProtocol.ProtocolMetaModel;
import java.io.IOException;
import java.util.List;
class MyCreateStandaloneTypeBindingVisitorBase extends CreateStandaloneTypeBindingVisitorBase {
private final String name;
private final DomainGenerator generator;
public MyCreateStandaloneTypeBindingVisitorBase(DomainGenerator generator, ProtocolMetaModel.StandaloneType type, String name) {
super(generator, type);
this.generator = generator;
this.name = name;
}
@Override
public StandaloneTypeBinding visitObject(List<ProtocolMetaModel.ObjectProperty> properties) {
return new StandaloneTypeBinding() {
@Override
public BoxableType getJavaType() {
return new StandaloneType(generator.generator.naming.additionalParam.getFullName(generator.domain.domain(), name), "writeMessage");
}
@Override
public void generate() throws IOException {
generator.generateCommandAdditionalParam(getType());
}
@Override
public TypeData.Direction getDirection() {
return TypeData.Direction.OUTPUT;
}
};
}
@Override
public StandaloneTypeBinding visitEnum(List<String> enumConstants) {
throw new RuntimeException();
}
@Override
public StandaloneTypeBinding visitArray(final ProtocolMetaModel.ArrayItemType items) {
return generator.createTypedefTypeBinding(getType(), new StandaloneTypeBinding.Target() {
@Override
public BoxableType resolve(final ResolveContext context) {
return new ListType(generator.generator.resolveType(items, new ResolveAndGenerateScope() {
// This class is responsible for generating ad hoc type.
// If we ever are to do it, we should generate into string buffer and put strings inside TypeDef class
@Override
public String getDomainName() {
return generator.domain.domain();
}
@Override
public TypeData.Direction getTypeDirection() {
return TypeData.Direction.OUTPUT;
}
@Override
public <T extends ItemDescriptor> TypeDescriptor resolveType(T typedObject) {
throw new UnsupportedOperationException();
}
@Override
public BoxableType generateNestedObject(String description, List<ProtocolMetaModel.ObjectProperty> properties) {
return context.generateNestedObject("Item", description, properties);
}
}).getType());
}
}, generator.generator.naming.outputTypedef, TypeData.Direction.OUTPUT);
}
}
@@ -0,0 +1,44 @@
package org.jetbrains.protocolReader
class MyCreateStandaloneTypeBindingVisitorBase(private val generator: DomainGenerator, type: ProtocolMetaModel.StandaloneType, private val name: String) : CreateStandaloneTypeBindingVisitorBase(generator, type) {
override fun visitObject(properties: List<ProtocolMetaModel.ObjectProperty>?): StandaloneTypeBinding {
return object : StandaloneTypeBinding {
override fun getJavaType(): BoxableType {
return StandaloneType(generator.generator.naming.additionalParam.getFullName(generator.domain.domain(), name), "writeMessage")
}
override fun generate() {
generator.generateCommandAdditionalParam(type)
}
override fun getDirection(): TypeData.Direction? {
return TypeData.Direction.OUTPUT
}
}
}
override fun visitEnum(enumConstants: List<String>): StandaloneTypeBinding {
throw RuntimeException()
}
override fun visitArray(items: ProtocolMetaModel.ArrayItemType): StandaloneTypeBinding {
return generator.createTypedefTypeBinding(type, object : StandaloneTypeBinding.Target {
override fun resolve(context: StandaloneTypeBinding.Target.ResolveContext): BoxableType {
return ListType(generator.generator.resolveType(items, object : ResolveAndGenerateScope {
// This class is responsible for generating ad hoc type.
// If we ever are to do it, we should generate into string buffer and put strings inside TypeDef class
override fun getDomainName() = generator.domain.domain()
override fun getTypeDirection() = TypeData.Direction.OUTPUT
override fun <T : ItemDescriptor> resolveType(typedObject: T) = throw UnsupportedOperationException()
override fun generateNestedObject(description: String?, properties: List<ProtocolMetaModel.ObjectProperty>?): BoxableType {
return context.generateNestedObject("Item", description, properties)
}
}).type)
}
}, generator.generator.naming.outputTypedef, TypeData.Direction.OUTPUT)
}
}
@@ -1,45 +0,0 @@
package org.jetbrains.protocolReader;
class NamePath {
private final String lastComponent;
private final NamePath parent;
NamePath(String component) {
this(component, null);
}
NamePath(String component, NamePath parent) {
lastComponent = component;
this.parent = parent;
}
NamePath getParent() {
return parent;
}
String getLastComponent() {
return lastComponent;
}
int getLength() {
int res = 1;
for (NamePath current = this; current != null; current = current.getParent()) {
res++;
}
return res;
}
String getFullText() {
StringBuilder result = new StringBuilder();
fillFullPath(result);
return result.toString();
}
private void fillFullPath(StringBuilder result) {
if (parent != null) {
parent.fillFullPath(result);
result.append('.');
}
result.append(lastComponent);
}
}
@@ -0,0 +1,30 @@
package org.jetbrains.protocolReader
class NamePath(val lastComponent: String, val parent: NamePath? = null) {
fun getLength(): Int {
var res = 1
run {
var current: NamePath? = this
while (current != null) {
res++
current = current!!.parent
}
}
return res
}
fun getFullText(): String {
val result = StringBuilder()
fillFullPath(result)
return result.toString()
}
private fun fillFullPath(result: StringBuilder) {
if (parent != null) {
parent.fillFullPath(result)
result.append('.')
}
result.append(lastComponent)
}
}
@@ -1,245 +0,0 @@
package org.jetbrains.protocolReader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.io.JsonReaderEx;
import org.jetbrains.jsonProtocol.ItemDescriptor;
import org.jetbrains.jsonProtocol.ProtocolMetaModel;
import java.util.ArrayList;
import java.util.List;
class OutputClassScope extends ClassScope {
OutputClassScope(@NotNull DomainGenerator generator, @NotNull NamePath classNamePath) {
super(generator, classNamePath);
}
<P extends ItemDescriptor.Named> void generate(@NotNull TextOutput out, @Nullable List<P> parameters) {
if (parameters == null) {
return;
}
List<P> mandatoryParameters = new ArrayList<>();
List<P> optionalParameters = new ArrayList<>();
for (P parameter : parameters) {
if (parameter.optional()) {
optionalParameters.add(parameter);
}
else {
mandatoryParameters.add(parameter);
}
}
if (!mandatoryParameters.isEmpty()) {
generateConstructor(out, mandatoryParameters, null);
if (mandatoryParameters.size() == 1) {
P parameter = mandatoryParameters.get(0);
TypeDescriptor typeData = new OutputMemberScope(getName(parameter)).resolveType(parameter);
if (typeData.getType().getFullText().equals("int[]")) {
BoxableType[] types = new BoxableType[mandatoryParameters.size()];
types[0] = new ListType(BoxableType.INT) {
@Override
String getShortText(NamePath contextNamespace) {
return getFullText();
}
@Override
String getFullText() {
return "gnu.trove.TIntArrayList";
}
@Override
String getWriteMethodName() {
return "writeIntList";
}
};
out.newLine().newLine();
generateConstructor(out, mandatoryParameters, types);
types[0] = new ListType(BoxableType.INT) {
@Override
String getShortText(NamePath contextNamespace) {
return getFullText();
}
@Override
String getFullText() {
return "int";
}
@Override
String getWriteMethodName() {
return "writeSingletonIntArray";
}
};
out.newLine().newLine();
generateConstructor(out, mandatoryParameters, types);
}
}
}
// generate enum classes after constructor
for (P parameter : parameters) {
if (parameter.getEnum() != null) {
out.newLine().newLine();
appendEnumClass(out, parameter.description(), parameter.getEnum(), Generator.capitalizeFirstChar((parameter.name())));
}
}
for (P parameter : optionalParameters) {
out.newLine().newLine();
if (parameter.description() != null) {
out.append("/**").newLine().append(" * @param v ").append(parameter.description()).newLine().append(" */").newLine();
}
CharSequence type = new OutputMemberScope(parameter.name()).resolveType(parameter).getType().getShortText(getClassContextNamespace());
if (type.equals(JsonReaderEx.class.getCanonicalName())) {
type = "String";
}
out.append("public ").append(getShortClassName());
out.space().append(parameter.name()).append("(").append(type);
out.space().append("v").append(")").openBlock();
appendWriteValueInvocation(out, parameter, "v", null);
out.newLine().append("return this;");
out.closeBlock();
}
}
private <P extends ItemDescriptor.Named> void generateConstructor(@NotNull TextOutput out, @NotNull List<P> parameters, @Nullable BoxableType[] parameterTypes) {
boolean hasDoc = false;
for (P parameter : parameters) {
if (parameter.description() != null) {
hasDoc = true;
break;
}
}
if (hasDoc) {
out.append("/**").newLine();
for (P parameter : parameters) {
if (parameter.description() != null) {
out.append(" * @param " + parameter.name() + ' ' + parameter.description()).newLine();
}
}
out.append(" */").newLine();
}
out.append("public " + getShortClassName() + '(');
if (parameterTypes == null) {
parameterTypes = new BoxableType[parameters.size()];
}
writeMethodParameters(out, parameters, parameterTypes);
out.append(')');
out.openBlock(false);
writeWriteCalls(out, parameters, parameterTypes, null);
out.closeBlock();
}
<P extends ItemDescriptor.Named> void writeWriteCalls(@NotNull TextOutput out, @NotNull List<P> parameters, @NotNull BoxableType[] parameterTypes, @Nullable String qualifier) {
for (int i = 0, size = parameters.size(); i < size; i++) {
out.newLine();
if (qualifier != null) {
out.append(qualifier).append('.');
}
P parameter = parameters.get(i);
appendWriteValueInvocation(out, parameter, parameter.name(), parameterTypes[i]);
}
}
<P extends ItemDescriptor.Named> void writeMethodParameters(@NotNull TextOutput out, @NotNull List<P> parameters, @NotNull BoxableType[] parameterTypes) {
for (int i = 0, length = parameterTypes.length; i < length; i++) {
if (parameterTypes[i] == null) {
P parameter = parameters.get(i);
parameterTypes[i] = new OutputMemberScope(parameter.name()).resolveType(parameter).getType();
}
}
boolean needComa = false;
for (int i = 0, size = parameters.size(); i < size; i++) {
if (needComa) {
out.comma();
}
else {
needComa = true;
}
out.append(parameterTypes[i].getShortText(getClassContextNamespace()));
out.space().append(parameters.get(i).name());
}
}
private void appendWriteValueInvocation(TextOutput out, ItemDescriptor.Named parameter, String valueRefName, @Nullable BoxableType type) {
if (type == null) {
type = new OutputMemberScope(parameter.name()).resolveType(parameter).getType();
}
boolean blockOpened = false;
if (parameter.optional()) {
String nullValue;
if (parameter.name().equals("columnNumber") || parameter.name().equals("column")) {
// todo generic solution
nullValue = "-1";
}
else {
nullValue = null;
}
if (nullValue != null) {
blockOpened = true;
out.append("if (v != ").append(nullValue).append(")").openBlock();
}
else if (parameter.name().equals("enabled")) {
blockOpened = true;
out.append("if (!v)").openBlock();
}
else if (parameter.name().equals("ignoreCount")) {
blockOpened = true;
out.append("if (v > 0)").openBlock();
}
}
// todo CallArgument (we should allow write null as value)
out.append(parameter.name().equals("value") && type.getWriteMethodName().equals("writeString") ? "writeNullableString" : type.getWriteMethodName()).append("(");
out.quote(parameter.name()).comma().append(valueRefName).append(");");
if (blockOpened) {
out.closeBlock();
}
}
@Override
protected TypeData.Direction getTypeDirection() {
return TypeData.Direction.OUTPUT;
}
class OutputMemberScope extends MemberScope {
protected OutputMemberScope(String memberName) {
super(OutputClassScope.this, memberName);
}
@Override
public BoxableType generateEnum(final String description, final List<String> enumConstants) {
return new StandaloneType(new NamePath(Generator.capitalizeFirstChar(getMemberName()), getClassContextNamespace()), "writeEnum");
}
@Override
public BoxableType generateNestedObject(String description, List<ProtocolMetaModel.ObjectProperty> propertyList) {
throw new UnsupportedOperationException();
}
}
private static void appendEnumClass(TextOutput out, String description, List<String> enumConstants, String enumName) {
out.doc(description);
Enums.appendEnums(enumConstants, enumName, false, out);
out.newLine().append("private final String protocolValue;").newLine();
out.newLine().append(enumName).append("(String protocolValue)").openBlock();
out.append("this.protocolValue = protocolValue;").closeBlock();
out.newLine().newLine().append("public String toString()").openBlock();
out.append("return protocolValue;").closeBlock();
out.closeBlock();
}
}
@@ -0,0 +1,225 @@
package org.jetbrains.protocolReader
class OutputClassScope(generator: DomainGenerator, classNamePath: NamePath) : ClassScope(generator, classNamePath) {
fun <P : ItemDescriptor.Named> generate(out: TextOutput, parameters: List<P>?) {
if (parameters == null) {
return
}
val mandatoryParameters = ArrayList<P>()
val optionalParameters = ArrayList<P>()
for (parameter in parameters) {
if (parameter.optional()) {
optionalParameters.add(parameter)
}
else {
mandatoryParameters.add(parameter)
}
}
if (!mandatoryParameters.isEmpty()) {
generateConstructor(out, mandatoryParameters)
if (mandatoryParameters.size() == 1) {
val parameter = mandatoryParameters.get(0)
val typeData = OutputMemberScope(ClassScope.getName(parameter)).resolveType<P>(parameter)
if (typeData.type.getFullText() == "int[]") {
val types = arrayOfNulls<BoxableType>(mandatoryParameters.size())
types[0] = object : ListType(BoxableType.INT) {
override fun getShortText(contextNamespace: NamePath): String {
return getFullText()
}
override fun getFullText(): String {
return "gnu.trove.TIntArrayList"
}
override fun getWriteMethodName(): String {
return "writeIntList"
}
}
out.newLine().newLine()
generateConstructor(out, mandatoryParameters, types)
types[0] = object : ListType(BoxableType.INT) {
override fun getShortText(contextNamespace: NamePath): String {
return getFullText()
}
override fun getFullText(): String {
return "int"
}
override fun getWriteMethodName(): String {
return "writeSingletonIntArray"
}
}
out.newLine().newLine()
generateConstructor(out, mandatoryParameters, types)
}
}
}
// generate enum classes after constructor
for (parameter in parameters) {
if (parameter.getEnum() != null) {
out.newLine().newLine()
appendEnumClass(out, parameter.description(), parameter.getEnum()!!, Generator.capitalizeFirstChar((parameter.name())))
}
}
for (parameter in optionalParameters) {
out.newLine().newLine()
if (parameter.description() != null) {
out.append("/**").newLine().append(" * @param v ").append(parameter.description()!!).newLine().append(" */").newLine()
}
var type: CharSequence = OutputMemberScope(parameter.name()).resolveType<P>(parameter).type.getShortText(classContextNamespace)
if (type == javaClass<JsonReaderEx>().getCanonicalName()) {
type = "String"
}
out.append("public ").append(getShortClassName())
out.space().append(parameter.name()).append("(").append(type)
out.space().append("v").append(")").openBlock()
appendWriteValueInvocation(out, parameter, "v")
out.newLine().append("return this;")
out.closeBlock()
}
}
private fun <P : ItemDescriptor.Named> generateConstructor(out: TextOutput, parameters: List<P>, parameterTypes: Array<BoxableType?> = arrayOfNulls<BoxableType>(parameters.size())) {
var hasDoc = false
for (parameter in parameters) {
if (parameter.description() != null) {
hasDoc = true
break
}
}
if (hasDoc) {
out.append("/**").newLine()
for (parameter in parameters) {
if (parameter.description() != null) {
out.append(" * @param " + parameter.name() + ' ' + parameter.description()).newLine()
}
}
out.append(" */").newLine()
}
out.append("public " + getShortClassName() + '(')
writeMethodParameters(out, parameters, parameterTypes)
out.append(')')
out.openBlock(false)
writeWriteCalls(out, parameters, parameterTypes, null)
out.closeBlock()
}
fun <P : ItemDescriptor.Named> writeWriteCalls(out: TextOutput, parameters: List<P>, parameterTypes: Array<BoxableType?>, qualifier: String?) {
run {
var i = 0
val size = parameters.size()
while (i < size) {
out.newLine()
if (qualifier != null) {
out.append(qualifier).append('.')
}
val parameter = parameters.get(i)
appendWriteValueInvocation(out, parameter, parameter.name(), parameterTypes[i]!!)
i++
}
}
}
fun <P : ItemDescriptor.Named> writeMethodParameters(out: TextOutput, parameters: List<P>, parameterTypes: Array<BoxableType?>) {
run {
var i = 0
val length = parameterTypes.size()
while (i < length) {
if (parameterTypes[i] == null) {
val parameter = parameters.get(i)
parameterTypes[i] = OutputMemberScope(parameter.name()).resolveType<P>(parameter).type
}
i++
}
}
var needComa = false
run {
var i = 0
val size = parameters.size()
while (i < size) {
if (needComa) {
out.comma()
}
else {
needComa = true
}
out.append(parameterTypes[i]!!.getShortText(classContextNamespace))
out.space().append(parameters.get(i).name())
i++
}
}
}
private fun appendWriteValueInvocation(out: TextOutput, parameter: ItemDescriptor.Named, valueRefName: String, type: BoxableType = OutputMemberScope(parameter.name()).resolveType<ItemDescriptor.Named>(parameter).type) {
var blockOpened = false
if (parameter.optional()) {
val nullValue: String?
if (parameter.name() == "columnNumber" || parameter.name() == "column") {
// todo generic solution
nullValue = "-1"
}
else {
nullValue = null
}
if (nullValue != null) {
blockOpened = true
out.append("if (v != ").append(nullValue).append(")").openBlock()
}
else if (parameter.name() == "enabled") {
blockOpened = true
out.append("if (!v)").openBlock()
}
else if (parameter.name() == "ignoreCount") {
blockOpened = true
out.append("if (v > 0)").openBlock()
}
}
// todo CallArgument (we should allow write null as value)
out.append(if (parameter.name() == "value" && type.getWriteMethodName() == "writeString") "writeNullableString" else type.getWriteMethodName()).append("(")
out.quote(parameter.name()).comma().append(valueRefName).append(");")
if (blockOpened) {
out.closeBlock()
}
}
override fun getTypeDirection(): TypeData.Direction {
return TypeData.Direction.OUTPUT
}
inner class OutputMemberScope(memberName: String) : MemberScope(this@OutputClassScope, memberName) {
override fun generateEnum(description: String?, enumConstants: List<String>): BoxableType {
return StandaloneType(NamePath(Generator.capitalizeFirstChar(memberName), classContextNamespace), "writeEnum")
}
override fun generateNestedObject(description: String?, properties: List<ProtocolMetaModel.ObjectProperty>?) = throw UnsupportedOperationException()
}
private fun appendEnumClass(out: TextOutput, description: String?, enumConstants: List<String>, enumName: String) {
out.doc(description)
Enums.appendEnums(enumConstants, enumName, false, out)
out.newLine().append("private final String protocolValue;").newLine()
out.newLine().append(enumName).append("(String protocolValue)").openBlock()
out.append("this.protocolValue = protocolValue;").closeBlock()
out.newLine().newLine().append("public String toString()").openBlock()
out.append("return protocolValue;").closeBlock()
out.closeBlock()
}
}
@@ -1,35 +0,0 @@
package org.jetbrains.protocolReader;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
class ParserRootInterfaceItem implements Comparable<ParserRootInterfaceItem> {
final String domain;
final String name;
private final ClassNameScheme.Input nameScheme;
final String fullName;
public ParserRootInterfaceItem(String domain, String name, ClassNameScheme.Input nameScheme) {
this.domain = domain;
this.name = name;
this.nameScheme = nameScheme;
fullName = nameScheme.getFullName(domain, name).getFullText();
}
void writeCode(TextOutput out) throws IOException {
out.append("@org.jetbrains.jsonProtocol.JsonParseMethod").newLine();
out.append("public abstract ").append(fullName).space();
appendReadMethodName(out);
out.append("(").append(Util.JSON_READER_PARAMETER_DEF).append(")").semi().newLine();
}
void appendReadMethodName(TextOutput out) {
out.append(nameScheme.getParseMethodName(domain, name));
}
@Override
public int compareTo(@NotNull ParserRootInterfaceItem o) {
return fullName.compareTo(o.fullName);
}
}
@@ -0,0 +1,26 @@
package org.jetbrains.protocolReader
import org.jetbrains.protocolReader.ParserRootInterfaceItem
class ParserRootInterfaceItem(val domain: String, val name: String, private val nameScheme: ClassNameScheme.Input) : Comparable<ParserRootInterfaceItem> {
val fullName: String
init {
fullName = nameScheme.getFullName(domain, name).getFullText()
}
fun writeCode(out: TextOutput) {
out.append("@org.jetbrains.jsonProtocol.JsonParseMethod").newLine()
out.append("public abstract ").append(fullName).space()
appendReadMethodName(out)
out.append("(").append(JSON_READER_PARAMETER_DEF).append(")").semi().newLine()
}
fun appendReadMethodName(out: TextOutput) {
out.append(nameScheme.getParseMethodName(domain, name))
}
override fun compareTo(other: ParserRootInterfaceItem): Int {
return fullName.compareTo(other.fullName)
}
}
@@ -1,45 +0,0 @@
package org.jetbrains.protocolReader;
import org.jetbrains.io.JsonReaderEx;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jsonProtocol.ProtocolSchemaReaderImpl;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Files;
public class ProtocolModelGenerator {
public static void main(String[] args) throws IOException {
String outputDir = args[0];
String schemaUrl = args[1];
byte[] bytes;
if (schemaUrl.startsWith("http")) {
bytes = loadBytes(new URL(schemaUrl).openStream());
}
else {
bytes = Files.readAllBytes(FileSystems.getDefault().getPath(schemaUrl));
}
JsonReaderEx reader = new JsonReaderEx(new String(bytes, StandardCharsets.UTF_8));
reader.setLenient(true);
new Generator(outputDir, args[2], args[3]).go(new ProtocolSchemaReaderImpl().parseRoot(reader));
}
@NotNull
public static byte[] loadBytes(@NotNull InputStream stream) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream(Math.max(stream.available(), 16 * 1024));
byte[] bytes = new byte[1024 * 20];
while (true) {
int n = stream.read(bytes, 0, bytes.length);
if (n <= 0) {
break;
}
buffer.write(bytes, 0, n);
}
buffer.close();
return buffer.toByteArray();
}
}
@@ -0,0 +1,40 @@
package org.jetbrains.protocolReader
import org.jetbrains.protocolReader.ProtocolModelGenerator
public class ProtocolModelGenerator {
default object {
throws(javaClass<IOException>())
public fun main(args: Array<String>) {
val outputDir = args[0]
val schemaUrl = args[1]
val bytes: ByteArray
if (schemaUrl.startsWith("http")) {
bytes = loadBytes(URL(schemaUrl).openStream())
}
else {
bytes = Files.readAllBytes(FileSystems.getDefault().getPath(schemaUrl))
}
val reader = JsonReaderEx(String(bytes, StandardCharsets.UTF_8))
reader.setLenient(true)
Generator(outputDir, args[2], args[3]).go(ProtocolSchemaReaderImpl().parseRoot(reader))
}
throws(javaClass<IOException>())
public fun loadBytes(stream: InputStream): ByteArray {
val buffer = ByteArrayOutputStream(Math.max(stream.available(), 16 * 1024))
val bytes = ByteArray(1024 * 20)
while (true) {
val n = stream.read(bytes, 0, bytes.size())
if (n <= 0) {
break
}
buffer.write(bytes, 0, n)
}
buffer.close()
return buffer.toByteArray()
}
}
}
fun main(args: Array<String>) = ProtocolModelGenerator.main(args)
@@ -1,16 +0,0 @@
package org.jetbrains.protocolReader;
import org.jetbrains.jsonProtocol.ItemDescriptor;
import org.jetbrains.jsonProtocol.ProtocolMetaModel;
import java.util.List;
interface ResolveAndGenerateScope {
String getDomainName();
TypeData.Direction getTypeDirection();
<T extends ItemDescriptor> TypeDescriptor resolveType(T typedObject);
BoxableType generateNestedObject(String description,
List<ProtocolMetaModel.ObjectProperty> properties);
}
@@ -0,0 +1,10 @@
package org.jetbrains.protocolReader
trait ResolveAndGenerateScope {
public fun getDomainName(): String
public fun getTypeDirection(): TypeData.Direction
public fun <T : ItemDescriptor> resolveType(typedObject: T): TypeDescriptor
public fun generateNestedObject(description: String?, properties: List<ProtocolMetaModel.ObjectProperty>?): BoxableType
}
@@ -1,62 +0,0 @@
package org.jetbrains.protocolReader;
class StandaloneType extends BoxableType {
private final NamePath namePath;
private final String writeMethodName;
StandaloneType(NamePath namePath, String writeMethodName) {
this.namePath = namePath;
this.writeMethodName = writeMethodName;
}
@Override
String getWriteMethodName() {
return writeMethodName;
}
@Override
CharSequence getFullText() {
return namePath.getFullText();
}
@Override
String getShortText(NamePath contextNamespace) {
int nameLength = namePath.getLength();
int contextLength = contextNamespace.getLength();
if (nameLength > contextLength) {
StringBuilder builder = subtractContextRecursively(namePath, nameLength - contextLength, contextNamespace);
if (builder != null) {
return builder.toString();
}
}
return namePath.getFullText();
}
private static StringBuilder subtractContextRecursively(NamePath namePos, int count, NamePath prefix) {
if (count > 1) {
StringBuilder result = subtractContextRecursively(namePos.getParent(), count - 1, prefix);
if (result == null) {
return null;
}
result.append('.');
result.append(namePos.getLastComponent());
return result;
}
else {
String nameComponent = namePos.getLastComponent();
namePos = namePos.getParent();
do {
if (!namePos.getLastComponent().equals(prefix.getLastComponent())) {
return null;
}
namePos = namePos.getParent();
prefix = prefix.getParent();
}
while (namePos != null);
StringBuilder result = new StringBuilder();
result.append(nameComponent);
return result;
}
}
}
@@ -0,0 +1,53 @@
package org.jetbrains.protocolReader
class StandaloneType(private val namePath: NamePath, private val writeMethodName: String) : BoxableType() {
override fun getWriteMethodName(): String {
return writeMethodName
}
override fun getFullText(): CharSequence {
return namePath.getFullText()
}
override fun getShortText(contextNamespace: NamePath): String {
val nameLength = namePath.getLength()
val contextLength = contextNamespace.getLength()
if (nameLength > contextLength) {
val builder = subtractContextRecursively(namePath, nameLength - contextLength, contextNamespace)
if (builder != null) {
return builder.toString()
}
}
return namePath.getFullText()
}
private fun subtractContextRecursively(namePos: NamePath?, count: Int, prefix: NamePath): StringBuilder? {
var namePos = namePos
var prefix = prefix
if (count > 1) {
val result = subtractContextRecursively(namePos!!.parent, count - 1, prefix)
if (result == null) {
return null
}
result.append('.')
result.append(namePos!!.lastComponent)
return result
}
else {
val nameComponent = namePos!!.lastComponent
namePos = namePos!!.parent
do {
if (namePos!!.lastComponent != prefix.lastComponent) {
return null
}
namePos = namePos!!.parent
prefix = prefix.parent!!
}
while (namePos != null)
val result = StringBuilder()
result.append(nameComponent)
return result
}
}
}
@@ -1,45 +0,0 @@
package org.jetbrains.protocolReader;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jsonProtocol.ProtocolMetaModel;
import java.io.IOException;
import java.util.List;
interface StandaloneTypeBinding {
BoxableType getJavaType();
void generate() throws IOException;
/**
* @return null if not direction-specific
*/
@Nullable
TypeData.Direction getDirection();
interface Target {
BoxableType resolve(ResolveContext context);
interface ResolveContext {
BoxableType generateNestedObject(String shortName, String description, List<ProtocolMetaModel.ObjectProperty> properties);
}
}
class PredefinedTarget implements Target {
private final BoxableType resolvedType;
PredefinedTarget(BoxableType resolvedType) {
this.resolvedType = resolvedType;
}
@Override
public BoxableType resolve(ResolveContext context) {
return resolvedType;
}
public static final PredefinedTarget STRING = new PredefinedTarget(BoxableType.STRING);
public static final PredefinedTarget INT = new PredefinedTarget(BoxableType.INT);
public static final PredefinedTarget NUMBER = new PredefinedTarget(BoxableType.NUMBER);
public static final PredefinedTarget MAP = new PredefinedTarget(BoxableType.MAP);
}
}
@@ -0,0 +1,35 @@
package org.jetbrains.protocolReader
trait StandaloneTypeBinding {
public fun getJavaType(): BoxableType
public fun generate()
/**
* @return null if not direction-specific
*/
public fun getDirection(): TypeData.Direction?
public trait Target {
public fun resolve(context: ResolveContext): BoxableType
public trait ResolveContext {
public fun generateNestedObject(shortName: String, description: String?, properties: List<ProtocolMetaModel.ObjectProperty>?): BoxableType
}
}
public class PredefinedTarget(private val resolvedType: BoxableType) : Target {
override fun resolve(context: Target.ResolveContext): BoxableType {
return resolvedType
}
default object {
public val STRING: PredefinedTarget = PredefinedTarget(BoxableType.STRING)
public val INT: PredefinedTarget = PredefinedTarget(BoxableType.INT)
public val NUMBER: PredefinedTarget = PredefinedTarget(BoxableType.NUMBER)
public val MAP: PredefinedTarget = PredefinedTarget(BoxableType.MAP)
}
}
}
@@ -1,5 +0,0 @@
package org.jetbrains.protocolReader;
public interface TextOutConsumer {
void append(TextOutput out);
}
@@ -0,0 +1,5 @@
package org.jetbrains.protocolReader
public trait TextOutConsumer {
public fun append(out: TextOutput)
}
@@ -1,176 +0,0 @@
package org.jetbrains.protocolReader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jsonProtocol.ProtocolMetaModel;
class TypeData {
public static final StandaloneTypeBinding ANY = new StandaloneTypeBinding() {
@Override
public BoxableType getJavaType() {
return BoxableType.ANY_STRING;
}
@Override
public void generate() {
}
@Override
public Direction getDirection() {
return null;
}
};
private final String name;
private Input input;
private Output output;
private ProtocolMetaModel.StandaloneType type;
private StandaloneTypeBinding commonBinding;
TypeData(String name) {
this.name = name;
}
void setType(@NotNull ProtocolMetaModel.StandaloneType type) {
this.type = type;
}
Input getInput() {
if (input == null) {
input = new Input();
}
return input;
}
Output getOutput() {
if (output == null) {
output = new Output();
}
return output;
}
TypeRef get(Direction direction) {
return direction.get(this);
}
void checkComplete() {
if (input != null) {
input.checkResolved();
}
if (output != null) {
output.checkResolved();
}
}
enum Direction {
INPUT() {
@Override
TypeRef get(TypeData typeData) {
return typeData.getInput();
}
},
OUTPUT() {
@Override
TypeRef get(TypeData typeData) {
return typeData.getOutput();
}
};
abstract TypeRef get(TypeData typeData);
}
abstract class TypeRef {
private StandaloneTypeBinding oneDirectionBinding;
BoxableType resolve(@NotNull TypeMap typeMap, @NotNull DomainGenerator domainGenerator) {
if (commonBinding != null) {
return commonBinding.getJavaType();
}
if (oneDirectionBinding != null) {
return oneDirectionBinding.getJavaType();
}
StandaloneTypeBinding binding = resolveImpl(domainGenerator);
if (binding == null) {
return null;
}
if (binding.getDirection() == null) {
commonBinding = binding;
}
else {
oneDirectionBinding = binding;
}
typeMap.addTypeToGenerate(binding);
return binding.getJavaType();
}
abstract StandaloneTypeBinding resolveImpl(DomainGenerator domainGenerator);
void checkResolved() {
if (type == null && !(name.equals("int") || name.equals("any"))) {
throw new RuntimeException();
}
}
}
class Output extends TypeRef {
@Override
StandaloneTypeBinding resolveImpl(@NotNull DomainGenerator domainGenerator) {
if (type == null) {
if (name.equals("int")) {
return new StandaloneTypeBinding() {
@Override
public BoxableType getJavaType() {
return BoxableType.INT;
}
@Override
public void generate() {
}
@Override
public Direction getDirection() {
return null;
}
};
}
else if (name.equals("any")) {
return ANY;
}
throw new RuntimeException();
}
return domainGenerator.createStandaloneOutputTypeBinding(type, name);
}
}
class Input extends TypeRef {
@Override
StandaloneTypeBinding resolveImpl(@NotNull DomainGenerator domainGenerator) {
if (type == null) {
if (name.equals("int")) {
return new StandaloneTypeBinding() {
@Override
public BoxableType getJavaType() {
return BoxableType.INT;
}
@Override
public void generate() {
}
@Override
public Direction getDirection() {
return null;
}
};
}
else if (name.equals("any")) {
return ANY;
}
throw new RuntimeException();
}
return domainGenerator.createStandaloneInputTypeBinding(type);
}
}
}
@@ -0,0 +1,159 @@
package org.jetbrains.protocolReader
import org.jetbrains.protocolReader.TypeData
class TypeData(private val name: String) {
private var input: Input? = null
private var output: Output? = null
private var type: ProtocolMetaModel.StandaloneType? = null
private var commonBinding: StandaloneTypeBinding? = null
fun setType(type: ProtocolMetaModel.StandaloneType) {
this.type = type
}
fun getInput(): Input {
if (input == null) {
input = Input()
}
return input!!
}
fun getOutput(): Output {
if (output == null) {
output = Output()
}
return output!!
}
fun get(direction: Direction): TypeRef {
return direction.get(this)
}
fun checkComplete() {
if (input != null) {
input!!.checkResolved()
}
if (output != null) {
output!!.checkResolved()
}
}
abstract class Direction {
default object {
val INPUT = object : Direction() {
override fun get(typeData: TypeData) = typeData.getInput()
}
val OUTPUT = object : Direction() {
override fun get(typeData: TypeData) = typeData.getOutput()
}
}
abstract fun get(typeData: TypeData): TypeRef
}
abstract inner class TypeRef {
private var oneDirectionBinding: StandaloneTypeBinding? = null
fun resolve(typeMap: TypeMap, domainGenerator: DomainGenerator): BoxableType? {
if (commonBinding != null) {
return commonBinding!!.getJavaType()
}
if (oneDirectionBinding != null) {
return oneDirectionBinding!!.getJavaType()
}
val binding = resolveImpl(domainGenerator)
if (binding == null) {
return null
}
if (binding.getDirection() == null) {
commonBinding = binding
}
else {
oneDirectionBinding = binding
}
typeMap.addTypeToGenerate(binding)
return binding.getJavaType()
}
abstract fun resolveImpl(domainGenerator: DomainGenerator): StandaloneTypeBinding?
fun checkResolved() {
if (type == null && !(name == "int" || name == "any")) {
throw RuntimeException()
}
}
}
inner class Output : TypeRef() {
override fun resolveImpl(domainGenerator: DomainGenerator): StandaloneTypeBinding? {
if (type == null) {
if (name == "int") {
return object : StandaloneTypeBinding {
override fun getJavaType(): BoxableType {
return BoxableType.INT
}
override fun generate() {
}
override fun getDirection(): Direction? {
return null
}
}
}
else if (name == "any") {
return ANY
}
throw RuntimeException()
}
return domainGenerator.createStandaloneOutputTypeBinding(type!!, name)
}
}
inner class Input : TypeRef() {
override fun resolveImpl(domainGenerator: DomainGenerator): StandaloneTypeBinding? {
if (type == null) {
if (name == "int") {
return object : StandaloneTypeBinding {
override fun getJavaType(): BoxableType {
return BoxableType.INT
}
override fun generate() {
}
override fun getDirection(): Direction? {
return null
}
}
}
else if (name == "any") {
return ANY
}
throw RuntimeException()
}
return domainGenerator.createStandaloneInputTypeBinding(type!!)
}
}
default object {
public val ANY: StandaloneTypeBinding = object : StandaloneTypeBinding {
override fun getJavaType(): BoxableType {
return BoxableType.ANY_STRING
}
override fun generate() {
}
override fun getDirection(): Direction? {
return null
}
}
}
}
@@ -1,50 +0,0 @@
package org.jetbrains.protocolReader;
import org.jetbrains.annotations.NotNull;
class TypeDescriptor {
private final BoxableType type;
private final boolean optional;
private final boolean nullable;
private final boolean asRawString;
TypeDescriptor(@NotNull BoxableType type, boolean optional) {
this(type, optional, false, false);
}
TypeDescriptor(@NotNull BoxableType type, boolean optional, boolean nullable, boolean asRawString) {
this.type = type;
this.optional = optional;
this.nullable = nullable;
this.asRawString = asRawString;
}
boolean isNullable() {
return nullable;
}
@NotNull
BoxableType getType() {
return type;
}
void writeAnnotations(@NotNull TextOutput out) {
if (optional || asRawString) {
out.append("@org.jetbrains.jsonProtocol.JsonField(");
if (optional) {
out.append("optional=true");
}
if (asRawString) {
if (optional) {
out.append(", ");
}
out.append("allowAnyPrimitiveValue=true");
}
out.append(")").newLine();
}
if (isNullable()) {
out.append("@org.jetbrains.jsonProtocol.JsonNullable").newLine();
}
}
}
@@ -0,0 +1,28 @@
package org.jetbrains.protocolReader
class TypeDescriptor(val type: BoxableType, private val optional: Boolean, private val nullable: Boolean = false, private val asRawString: Boolean = false) {
fun isNullable(): Boolean {
return nullable
}
fun writeAnnotations(out: TextOutput) {
if (optional || asRawString) {
out.append("@org.jetbrains.jsonProtocol.JsonField(")
if (optional) {
out.append("optional=true")
}
if (asRawString) {
if (optional) {
out.append(", ")
}
out.append("allowAnyPrimitiveValue=true")
}
out.append(")").newLine()
}
if (isNullable()) {
out.append("@org.jetbrains.jsonProtocol.JsonNullable").newLine()
}
}
}
@@ -1,61 +0,0 @@
package org.jetbrains.protocolReader;
import com.intellij.openapi.util.Pair;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Keeps track of all referenced types.
* A type may be used and resolved (generated or hard-coded).
*/
class TypeMap {
private final Map<Pair<String, String>, TypeData> map = new THashMap<>();
private Map<String, DomainGenerator> domainGeneratorMap;
private final List<StandaloneTypeBinding> typesToGenerate = new ArrayList<>();
void setDomainGeneratorMap(Map<String, DomainGenerator> domainGeneratorMap) {
this.domainGeneratorMap = domainGeneratorMap;
}
@Nullable
BoxableType resolve(String domainName, String typeName, TypeData.Direction direction) {
DomainGenerator domainGenerator = domainGeneratorMap.get(domainName);
if (domainGenerator == null) {
throw new RuntimeException("Failed to find domain generator: " + domainName);
}
return getTypeData(domainName, typeName).get(direction).resolve(this, domainGenerator);
}
void addTypeToGenerate(@NotNull StandaloneTypeBinding binding) {
typesToGenerate.add(binding);
}
public void generateRequestedTypes() throws IOException {
// Size may grow during iteration.
//noinspection ForLoopReplaceableByForEach
for (int i = 0; i < typesToGenerate.size(); i++) {
typesToGenerate.get(i).generate();
}
for (TypeData typeData : map.values()) {
typeData.checkComplete();
}
}
@NotNull
TypeData getTypeData(@NotNull String domainName, @NotNull String typeName) {
Pair<String, String> key = Pair.create(domainName, typeName);
TypeData result = map.get(key);
if (result == null) {
result = new TypeData(typeName);
map.put(key, result);
}
return result;
}
}
@@ -0,0 +1,50 @@
package org.jetbrains.protocolReader
/**
* Keeps track of all referenced types.
* A type may be used and resolved (generated or hard-coded).
*/
class TypeMap {
private val map = THashMap<Pair<String, String>, TypeData>()
private var domainGeneratorMap: Map<String, DomainGenerator>? = null
private val typesToGenerate = ArrayList<StandaloneTypeBinding>()
fun setDomainGeneratorMap(domainGeneratorMap: Map<String, DomainGenerator>) {
this.domainGeneratorMap = domainGeneratorMap
}
fun resolve(domainName: String, typeName: String, direction: TypeData.Direction): BoxableType? {
val domainGenerator = domainGeneratorMap!!.get(domainName)
if (domainGenerator == null) {
throw RuntimeException("Failed to find domain generator: " + domainName)
}
return getTypeData(domainName, typeName).get(direction).resolve(this, domainGenerator)
}
fun addTypeToGenerate(binding: StandaloneTypeBinding) {
typesToGenerate.add(binding)
}
throws(javaClass<IOException>())
public fun generateRequestedTypes() {
// Size may grow during iteration.
//noinspection ForLoopReplaceableByForEach
for (i in typesToGenerate.indices) {
typesToGenerate.get(i).generate()
}
for (typeData in map.values()) {
typeData.checkComplete()
}
}
fun getTypeData(domainName: String, typeName: String): TypeData {
val key = Pair.create<String, String>(domainName, typeName)
var result: TypeData? = map.get(key)
if (result == null) {
result = TypeData(typeName)
map.put(key, result)
}
return result!!
}
}
@@ -1,27 +0,0 @@
package org.jetbrains.protocolReader;
import org.jetbrains.jsonProtocol.ProtocolMetaModel;
import java.util.List;
interface TypeVisitor<R> {
R visitRef(String refName);
R visitBoolean();
R visitEnum(List<String> enumConstants);
R visitString();
R visitInteger();
R visitNumber();
R visitArray(ProtocolMetaModel.ArrayItemType items);
R visitObject(List<ProtocolMetaModel.ObjectProperty> properties);
R visitMap();
R visitUnknown();
}
@@ -0,0 +1,23 @@
package org.jetbrains.protocolReader
trait TypeVisitor<R> {
public fun visitRef(refName: String): R
public fun visitBoolean(): R
public fun visitEnum(enumConstants: List<String>): R
public fun visitString(): R
public fun visitInteger(): R
public fun visitNumber(): R
public fun visitArray(items: ProtocolMetaModel.ArrayItemType): R
public fun visitObject(properties: List<ProtocolMetaModel.ObjectProperty>?): R
public fun visitMap(): R
public fun visitUnknown(): R
}
@@ -1,7 +1,6 @@
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.jetbrains.jsonProtocol;
import java.lang.annotation.ElementType;
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
@@ -4,10 +4,11 @@ import gnu.trove.THashSet
import org.jetbrains.jsonProtocol.JsonField
import org.jetbrains.jsonProtocol.JsonOptionalField
import org.jetbrains.jsonProtocol.JsonSubtypeCasting
import java.lang.reflect.Method
import java.lang.reflect.ParameterizedType
import java.util.*
import java.util.ArrayList
import java.util.Arrays
import java.util.LinkedHashMap
class FieldProcessor(private val reader: InterfaceReader, typeClass: Class<*>) {
val fieldLoaders = ArrayList<FieldLoader>()
@@ -15,10 +16,10 @@ class FieldProcessor(private val reader: InterfaceReader, typeClass: Class<*>) {
val volatileFields = ArrayList<VolatileFieldBinding>()
var lazyRead: Boolean = false
{
init {
val methods = typeClass.getMethods()
// todo sort by source location
Arrays.sort(methods, {(o1, o2) -> o1.getName().compareTo(o2.getName())})
Arrays.sort(methods, {(o1, o2) -> o1.getName().compareTo(o2.getName()) })
val skippedNames = THashSet<String>()
for (method in methods) {
@@ -40,7 +40,7 @@ private class State(typeWriters: Collection<TypeWriter<*>>, private val basePack
private val typesWithFactories = THashSet<TypeWriter<*>>()
val typesWithFactoriesList = ArrayList<TypeWriter<*>>();
{
init {
var uniqueCode = 0
val result = THashMap<TypeWriter<*>, String>(typeWriters.size())
for (handler in typeWriters) {
@@ -1,16 +1,17 @@
package org.jetbrains.protocolReader
import gnu.trove.THashSet
import org.jetbrains.io.JsonReaderEx
import org.jetbrains.jsonProtocol.JsonField
import org.jetbrains.jsonProtocol.JsonOptionalField
import org.jetbrains.jsonProtocol.JsonSubtype
import org.jetbrains.jsonProtocol.StringIntPair
import java.lang.reflect.Method
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import java.lang.reflect.WildcardType
import java.util.*
import gnu.trove.*
import java.util.ArrayList
import java.util.LinkedHashMap
fun InterfaceReader(protocolInterfaces: Array<Class<*>>): InterfaceReader {
val __ = InterfaceReader(LinkedHashMap<Class<*>, TypeWriter<*>>(protocolInterfaces.size()))
@@ -130,6 +131,9 @@ class InterfaceReader(val typeToTypeHandler: LinkedHashMap<Class<*>, TypeWriter<
if (jsonField != null && jsonField.allowAnyPrimitiveValue()) {
return RAW_STRING_PARSER
}
else if ((jsonField != null && jsonField.optional()) || method.getAnnotation<JsonOptionalField>(javaClass<JsonOptionalField>()) != null) {
return NULLABLE_STRING_PARSER
}
}
return STRING_PARSER
}
@@ -220,6 +224,7 @@ class InterfaceReader(val typeToTypeHandler: LinkedHashMap<Class<*>, TypeWriter<
private val NUMBER_PARSER = PrimitiveValueReader("double")
private val STRING_PARSER = PrimitiveValueReader("String")
private val NULLABLE_STRING_PARSER = PrimitiveValueReader(className = "String", nullable = true)
private val RAW_STRING_PARSER = PrimitiveValueReader("String", null, true)
private val RAW_STRING_OR_MAP_PARSER = object : PrimitiveValueReader("Object", null, true) {
@@ -1,18 +1,9 @@
package org.jetbrains.protocolReader
fun PrimitiveValueReader(name: String): PrimitiveValueReader {
return PrimitiveValueReader(name, null, false)
}
fun PrimitiveValueReader(name: String, defaultValue: String): PrimitiveValueReader {
return PrimitiveValueReader(name, defaultValue, false)
}
open class PrimitiveValueReader(private val className: String, val defaultValue: String?, private val asRawString: Boolean) : ValueReader() {
open class PrimitiveValueReader(private val className: String, val defaultValue: String? = null, private val asRawString: Boolean = false, private val nullable: Boolean = false) : ValueReader() {
private val readPostfix: String
{
init {
if (Character.isLowerCase(className.charAt(0))) {
readPostfix = Character.toUpperCase(className.charAt(0)) + className.substring(1)
}
@@ -29,7 +20,11 @@ open class PrimitiveValueReader(private val className: String, val defaultValue:
}
else {
addReaderParameter(subtyping, out)
out.append(".next").append(readPostfix).append("()")
out.append(".next");
if (nullable) {
out.append("Nullable");
}
out.append(readPostfix).append("()")
//beginReadCall(readPostfix, subtyping, out, name);
}
}
@@ -1,13 +1,12 @@
package org.jetbrains.protocolReader
import gnu.trove.THashMap
import java.io.File
import java.nio.file.FileSystems
import java.util.*
import java.util.HashMap
import java.util.LinkedHashMap
public class ReaderGenerator {
public class GenerateConfiguration<ROOT>(val packageName: String, val className: String, readerRootClass: Class<ROOT>, protocolInterfaces: Array<Class<*>>, basePackagesMap: Map<Class<*>, String>? = null) {
val basePackagesMap: Collection<Map<Class<*>, String>>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
@@ -9,6 +9,7 @@
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="gson" level="project" />
<orderEntry type="module" module-name="protocol-reader" />
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
<orderEntry type="module" module-name="platform-impl" />
</component>
</module>
</module>
@@ -1,30 +0,0 @@
package org.jetbrains.jsonProtocol;
import java.util.List;
public interface ItemDescriptor {
String description();
String type();
List<String> getEnum();
ProtocolMetaModel.ArrayItemType items();
interface Named extends Referenceable {
String name();
@JsonOptionalField
String shortName();
boolean optional();
}
interface Referenceable extends ItemDescriptor {
String ref();
}
interface Type extends ItemDescriptor {
List<ProtocolMetaModel.ObjectProperty> properties();
}
}
@@ -0,0 +1,28 @@
package org.jetbrains.jsonProtocol
public trait ItemDescriptor {
public fun description(): String?
public fun type(): String
public fun getEnum(): List<String>?
public fun items(): ProtocolMetaModel.ArrayItemType
public trait Named : Referenceable {
public fun name(): String
JsonOptionalField
public fun shortName(): String?
public fun optional(): Boolean
}
public trait Referenceable : ItemDescriptor {
public fun ref(): String
}
public trait Type : ItemDescriptor {
public fun properties(): List<ProtocolMetaModel.ObjectProperty>?
}
}
@@ -1,223 +0,0 @@
package org.jetbrains.jsonProtocol;
import java.util.List;
/**
* Defines schema of WIP metamodel defined in http://svn.webkit.org/repository/webkit/trunk/Source/WebCore/inspector/Inspector.json
*/
public interface ProtocolMetaModel {
@JsonType
interface Root {
@JsonOptionalField
Version version();
List<Domain> domains();
}
@JsonType
interface Version {
String major();
String minor();
}
@JsonType
interface Domain {
String domain();
@JsonOptionalField
List<StandaloneType> types();
List<Command> commands();
@JsonOptionalField
List<Event> events();
@JsonOptionalField
String description();
@JsonOptionalField
boolean hidden();
}
@JsonType
interface Command {
String name();
@JsonOptionalField
List<Parameter> parameters();
@JsonOptionalField
List<Parameter> returns();
@JsonOptionalField
String description();
@JsonOptionalField
boolean hidden();
@JsonOptionalField
boolean async();
}
@JsonType
interface Parameter extends ItemDescriptor.Named {
@Override
String name();
@Override
@JsonOptionalField
String shortName();
@Override
@JsonOptionalField
String type();
@Override
@JsonOptionalField
ArrayItemType items();
@Override
@JsonField(jsonLiteralName = "enum")
@JsonOptionalField
List<String> getEnum();
@Override
@JsonOptionalField
@JsonField(jsonLiteralName = "$ref")
String ref();
@Override
@JsonOptionalField
boolean optional();
@Override
@JsonOptionalField
String description();
@JsonOptionalField
boolean hidden();
}
@JsonType
interface Event {
String name();
@JsonOptionalField
List<Parameter> parameters();
@JsonOptionalField
String description();
@JsonOptionalField
boolean hidden();
}
@JsonType
interface StandaloneType extends ItemDescriptor.Type {
String id();
@Override
@JsonOptionalField
String description();
@Override
String type();
@JsonOptionalField
boolean hidden();
@Override
@JsonOptionalField
List<ObjectProperty> properties();
@Override
@JsonField(jsonLiteralName = "enum")
@JsonOptionalField
List<String> getEnum();
@Override
@JsonOptionalField
ArrayItemType items();
}
@JsonType
interface ArrayItemType extends ItemDescriptor.Type, ItemDescriptor.Referenceable {
@Override
@JsonOptionalField
String description();
@JsonOptionalField
boolean optional();
@Override
@JsonOptionalField
String type();
@Override
@JsonOptionalField
ArrayItemType items();
@Override
@JsonField(jsonLiteralName = "$ref")
@JsonOptionalField
String ref();
@Override
@JsonField(jsonLiteralName = "enum")
@JsonOptionalField
List<String> getEnum();
@Override
@JsonOptionalField
List<ObjectProperty> properties();
}
@JsonType
interface ObjectProperty extends ItemDescriptor.Named {
@Override
String name();
@Override
@JsonOptionalField
String shortName();
@Override
@JsonOptionalField
String description();
@Override
@JsonOptionalField
boolean optional();
@Override
@JsonOptionalField
String type();
@Override
@JsonOptionalField
ArrayItemType items();
@Override
@JsonField(jsonLiteralName = "$ref")
@JsonOptionalField
String ref();
@Override
@JsonField(jsonLiteralName = "enum")
@JsonOptionalField
List<String> getEnum();
@JsonOptionalField
boolean hidden();
}
String STRING_TYPE = "string";
String INTEGER_TYPE = "integer";
String NUMBER_TYPE = "number";
String BOOLEAN_TYPE = "boolean";
String OBJECT_TYPE = "object";
String ARRAY_TYPE = "array";
String UNKNOWN_TYPE = "unknown";
String ANY_TYPE = "any";
}
@@ -0,0 +1,196 @@
package org.jetbrains.jsonProtocol
/**
* Defines schema of WIP metamodel defined in http://svn.webkit.org/repository/webkit/trunk/Source/WebCore/inspector/Inspector.json
*/
public trait ProtocolMetaModel {
JsonType
public trait Root {
JsonOptionalField
public fun version(): Version
public fun domains(): List<Domain>
}
JsonType
public trait Version {
public fun major(): String
public fun minor(): String
}
JsonType
public trait Domain {
public fun domain(): String
JsonOptionalField
public fun types(): List<StandaloneType>?
public fun commands(): List<Command>
JsonOptionalField
public fun events(): List<Event>?
JsonOptionalField
public fun description(): String
JsonOptionalField
public fun hidden(): Boolean
}
JsonType
public trait Command {
public fun name(): String
JsonOptionalField
public fun parameters(): List<Parameter>?
JsonOptionalField
public fun returns(): List<Parameter>?
JsonOptionalField
public fun description(): String
JsonOptionalField
public fun hidden(): Boolean
JsonOptionalField
public fun async(): Boolean
}
JsonType
public trait Parameter : ItemDescriptor.Named {
override fun name(): String
JsonOptionalField
override fun shortName(): String
JsonOptionalField
override fun type(): String
JsonOptionalField
override fun items(): ArrayItemType
JsonField(name = "enum")
JsonOptionalField
override fun getEnum(): List<String>
JsonOptionalField
JsonField(name = "\$ref")
override fun ref(): String
JsonOptionalField
override fun optional(): Boolean
JsonOptionalField
override fun description(): String
JsonOptionalField
public fun hidden(): Boolean
}
JsonType
public trait Event {
public fun name(): String
JsonOptionalField
public fun parameters(): List<Parameter>
JsonOptionalField
public fun description(): String
JsonOptionalField
public fun hidden(): Boolean
}
JsonType
public trait StandaloneType : ItemDescriptor.Type {
public fun id(): String
JsonOptionalField
override fun description(): String?
override fun type(): String
JsonOptionalField
public fun hidden(): Boolean
JsonOptionalField
override fun properties(): List<ObjectProperty>
JsonField(name = "enum")
JsonOptionalField
override fun getEnum(): List<String>
JsonOptionalField
override fun items(): ArrayItemType
}
JsonType
public trait ArrayItemType : ItemDescriptor.Type, ItemDescriptor.Referenceable {
JsonOptionalField
override fun description(): String
JsonOptionalField
public fun optional(): Boolean
JsonOptionalField
override fun type(): String
JsonOptionalField
override fun items(): ArrayItemType
JsonField(name = "\$ref")
JsonOptionalField
override fun ref(): String
JsonField(name = "enum")
JsonOptionalField
override fun getEnum(): List<String>
JsonOptionalField
override fun properties(): List<ObjectProperty>
}
JsonType
public trait ObjectProperty : ItemDescriptor.Named {
override fun name(): String
JsonOptionalField
override fun shortName(): String
JsonOptionalField
override fun description(): String
JsonOptionalField
override fun optional(): Boolean
JsonOptionalField
override fun type(): String
JsonOptionalField
override fun items(): ArrayItemType
JsonField(name = "\$ref")
JsonOptionalField
override fun ref(): String
JsonField(name = "enum")
JsonOptionalField
override fun getEnum(): List<String>
JsonOptionalField
public fun hidden(): Boolean
}
default object {
public val STRING_TYPE: String = "string"
public val INTEGER_TYPE: String = "integer"
public val NUMBER_TYPE: String = "number"
public val BOOLEAN_TYPE: String = "boolean"
public val OBJECT_TYPE: String = "object"
public val ARRAY_TYPE: String = "array"
public val UNKNOWN_TYPE: String = "unknown"
public val ANY_TYPE: String = "any"
}
}
@@ -1,15 +0,0 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.jetbrains.jsonProtocol;
import org.jetbrains.io.JsonReaderEx;
import org.jetbrains.jsonProtocol.ProtocolMetaModel.Root;
import java.io.IOException;
public interface ProtocolSchemaReader {
@JsonParseMethod
Root parseRoot(JsonReaderEx reader) throws IOException;
}
@@ -0,0 +1,12 @@
package org.jetbrains.jsonProtocol
import org.jetbrains.io.JsonReaderEx
import org.jetbrains.jsonProtocol.ProtocolMetaModel.Root
import java.io.IOException
public trait ProtocolSchemaReader {
JsonParseMethod
throws(javaClass<IOException>())
public fun parseRoot(reader: JsonReaderEx): Root
}
@@ -1,11 +0,0 @@
package org.jetbrains.jsonProtocol;
import org.jetbrains.protocolReader.ReaderGenerator;
import java.io.IOException;
public class SchemaReaderGenerator {
public static void main(String[] args) throws IOException {
ReaderGenerator.generate(args, new ReaderGenerator.GenerateConfiguration<>("org.jetbrains.jsonProtocol", "ProtocolSchemaReaderImpl", ProtocolSchemaReader.class, ProtocolMetaModel.class.getDeclaredClasses()));
}
}
@@ -0,0 +1,5 @@
package org.jetbrains.jsonProtocol
import org.jetbrains.protocolReader.ReaderGenerator
fun main(args: Array<String>) = ReaderGenerator.generate(args, ReaderGenerator.GenerateConfiguration("org.jetbrains.jsonProtocol", "ProtocolSchemaReaderImpl", javaClass<ProtocolSchemaReader>(), javaClass<ProtocolMetaModel>().getDeclaredClasses()))
@@ -15,6 +15,7 @@
*/
package git4idea.commands;
import com.intellij.ide.passwordSafe.MasterPasswordUnavailableException;
import com.intellij.ide.passwordSafe.PasswordSafe;
import com.intellij.ide.passwordSafe.PasswordSafeException;
import com.intellij.ide.passwordSafe.impl.PasswordSafeImpl;
@@ -169,6 +170,8 @@ class GitHttpGuiAuthenticator implements GitHttpAuthenticator {
passwordSafe.getMasterKeyProvider().storePassword(myProject, PASS_REQUESTER, myPasswordKey, myPassword);
}
}
catch (MasterPasswordUnavailableException ignored) {
}
catch (PasswordSafeException e) {
LOG.error("Couldn't remember password for " + myPasswordKey, e);
}
@@ -503,13 +503,15 @@ public class GithubCreatePullRequestWorker {
String targetBranchName = "'" + fork.getRemoteName() + "/" + branch.getRemoteName() + "'";
if (info.getInfo().getBranchToHeadCommits(myGitRepository).isEmpty()) {
return GithubNotifications
.showYesNoDialog(myProject, "Do you want to proceed anyway?",
"Empty pull request: the branch " + localBranchName + " is fully merged to the branch " + targetBranchName);
.showYesNoDialog(myProject, "Empty Pull Request",
"The branch " + localBranchName + " is fully merged to the branch " + targetBranchName + '\n' +
"Do you want to proceed anyway?");
}
if (!info.getInfo().getHeadToBranchCommits(myGitRepository).isEmpty()) {
return GithubNotifications
.showYesNoDialog(myProject, "Do you want to proceed anyway?",
"The branch " + targetBranchName + " is not fully merged to the branch " + localBranchName);
.showYesNoDialog(myProject, "Target Branch Is Not Fully Merged",
"The branch " + targetBranchName + " is not fully merged to the branch " + localBranchName + '\n' +
"Do you want to proceed anyway?");
}
return true;
@@ -15,6 +15,7 @@
*/
package org.jetbrains.plugins.github;
import com.intellij.ide.BrowserUtil;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ServiceManager;
@@ -23,6 +24,7 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Ref;
@@ -33,6 +35,7 @@ import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vcs.changes.ui.SelectFilesDialog;
import com.intellij.openapi.vcs.ui.CommitMessage;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Function;
import com.intellij.util.ThrowableConvertor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashSet;
@@ -44,6 +47,7 @@ import git4idea.actions.BasicAction;
import git4idea.actions.GitInit;
import git4idea.commands.*;
import git4idea.i18n.GitBundle;
import git4idea.repo.GitRemote;
import git4idea.repo.GitRepository;
import git4idea.repo.GitRepositoryManager;
import git4idea.util.GitFileUtils;
@@ -62,9 +66,7 @@ import org.jetbrains.plugins.github.util.GithubUtil;
import javax.swing.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.*;
import static org.jetbrains.plugins.github.util.GithubUtil.setVisibleEnabled;
@@ -119,13 +121,19 @@ public class GithubShareAction extends DumbAwareAction {
final GithubAuthDataHolder authHolder = GithubAuthDataHolder.createFromSettings();
// check for existing git repo
boolean externalRemoteDetected = false;
Set<String> existingRemotes = Collections.emptySet();
if (gitDetected) {
final String githubRemote = GithubUtil.findGithubRemoteUrl(gitRepository);
if (githubRemote != null) {
if (!checkExistingRemote(project, authHolder, githubRemote)) return;
}
externalRemoteDetected = !gitRepository.getRemotes().isEmpty();
existingRemotes = ContainerUtil.map2Set(gitRepository.getRemotes(), new Function<GitRemote, String>() {
@Override
public String fun(GitRemote remote) {
return remote.getName();
}
});
}
// get available GitHub repos with modal progress
@@ -136,7 +144,7 @@ public class GithubShareAction extends DumbAwareAction {
// Show dialog (window)
final GithubShareDialog shareDialog =
new GithubShareDialog(project, githubInfo.getRepositoryNames(), githubInfo.getUser().canCreatePrivateRepo());
new GithubShareDialog(project, githubInfo.getRepositoryNames(), existingRemotes, githubInfo.getUser().canCreatePrivateRepo());
DialogManager.show(shareDialog);
if (!shareDialog.isOK()) {
return;
@@ -144,9 +152,8 @@ public class GithubShareAction extends DumbAwareAction {
final boolean isPrivate = shareDialog.isPrivate();
final String name = shareDialog.getRepositoryName();
final String description = shareDialog.getDescription();
final String remoteName = shareDialog.getRemoteName();
// finish the job in background
final boolean finalExternalRemoteDetected = externalRemoteDetected;
new Task.Backgroundable(project, "Sharing project on GitHub...") {
@Override
public void run(@NotNull ProgressIndicator indicator) {
@@ -178,7 +185,6 @@ public class GithubShareAction extends DumbAwareAction {
}
final String remoteUrl = GithubUrlUtil.getCloneUrl(githubInfo.getUser().getLogin(), name);
final String remoteName = finalExternalRemoteDetected ? "github" : "origin";
//git remote add origin git@github.com:login/name.git
LOG.info("Adding GitHub as a remote host");
@@ -210,7 +216,7 @@ public class GithubShareAction extends DumbAwareAction {
final GithubFullPath path = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(remote);
if (path == null) {
return GithubNotifications.showYesNoDialog(project,
"Project is already on GitHub",
"Project Is Already on GitHub",
"Can't connect to repository from configured remote. You could want to check .git config.\n" +
"Do you want to proceed anyway?");
}
@@ -231,22 +237,30 @@ public class GithubShareAction extends DumbAwareAction {
});
}
});
GithubNotifications.showInfoURL(project, "Project is already on GitHub", "GitHub", repo.getHtmlUrl());
int result = Messages.showDialog(project,
"Successfully connected to " + repo.getHtmlUrl() + ".\n" +
"Do you want to proceed anyway?",
"Project Is Already on GitHub",
new String[]{"Continue", "Open in Browser", Messages.CANCEL_BUTTON}, 2, Messages.getQuestionIcon());
if (result == 0) return true;
if (result == 1) {
BrowserUtil.browse(repo.getHtmlUrl());
}
return false;
}
catch (GithubStatusCodeException e) {
if (e.getStatusCode() == HttpStatus.SC_NOT_FOUND) {
return GithubNotifications.showYesNoDialog(project,
"Project is already on GitHub",
"Project Is Already on GitHub",
"Can't connect to repository from configured remote. You could want to check .git config.\n" +
"Do you want to proceed anyway?");
}
GithubNotifications.showErrorDialog(project, "Failed to connect to GitHub", e);
GithubNotifications.showErrorDialog(project, "Failed to Connect to GitHub", e);
return false;
}
catch (IOException e) {
GithubNotifications.showErrorDialog(project, "Failed to connect to GitHub", e);
GithubNotifications.showErrorDialog(project, "Failed to Connect to GitHub", e);
return false;
}
}
@@ -278,7 +292,7 @@ public class GithubShareAction extends DumbAwareAction {
});
}
catch (IOException e) {
GithubNotifications.showErrorDialog(project, "Failed to connect to GitHub", e);
GithubNotifications.showErrorDialog(project, "Failed to Connect to GitHub", e);
return null;
}
}
@@ -33,6 +33,7 @@ import org.jetbrains.plugins.github.api.GithubConnection;
import org.jetbrains.plugins.github.api.GithubRepo;
import org.jetbrains.plugins.github.util.GithubAuthDataHolder;
import org.jetbrains.plugins.github.util.GithubNotifications;
import org.jetbrains.plugins.github.util.GithubUrlUtil;
import org.jetbrains.plugins.github.util.GithubUtil;
import java.io.File;
@@ -88,7 +89,7 @@ public class GithubCheckoutProvider implements CheckoutProvider {
// Add predefined repositories to history
dialog.prependToHistory("-----------------------------------------------");
for (int i = availableRepos.size() - 1; i >= 0; i--) {
dialog.prependToHistory(availableRepos.get(i).getCloneUrl());
dialog.prependToHistory(GithubUrlUtil.getCloneUrl(availableRepos.get(i).getFullPath()));
}
if (!dialog.showAndGet()) {
return;
@@ -139,7 +139,7 @@ public class GithubRepositoryEditor extends BaseRepositoryEditor<GithubRepositor
);
}
catch (IOException e) {
GithubNotifications.showErrorDialog(myProject, "Can't get access token", e);
GithubNotifications.showErrorDialog(myProject, "Can't Get Access Token", e);
}
}
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.plugins.github.ui.GithubSettingsPanel">
<grid id="27dc6" binding="myPane" layout-manager="GridLayoutManager" row-count="6" column-count="5" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="27dc6" binding="myPane" layout-manager="GridLayoutManager" row-count="7" column-count="5" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="646" height="400"/>
@@ -28,7 +28,7 @@
</component>
<vspacer id="6ace">
<constraints>
<grid row="5" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
<grid row="6" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<component id="45bab" class="com.intellij.ui.components.JBLabel">
@@ -167,7 +167,7 @@
<grid id="d384a" layout-manager="GridLayoutManager" row-count="1" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="4" column="0" row-span="1" col-span="5" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="5" column="0" row-span="1" col-span="5" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<clientProperties>
@@ -204,7 +204,15 @@
</component>
</children>
</grid>
<vspacer id="2a9d8">
<component id="e2613" class="com.intellij.ui.components.JBCheckBox" binding="myCloneUsingSshCheckBox" default-binding="true">
<constraints>
<grid row="4" column="0" row-span="1" col-span="5" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Clone git repositories using ssh"/>
</properties>
</component>
<vspacer id="5f470">
<constraints>
<grid row="3" column="0" row-span="1" col-span="5" vsize-policy="0" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false">
<minimum-size width="-1" height="15"/>
@@ -25,6 +25,7 @@ import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.HyperlinkAdapter;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBLabel;
import com.intellij.util.ThrowableConvertor;
import org.jetbrains.annotations.NotNull;
@@ -33,7 +34,6 @@ import org.jetbrains.plugins.github.api.GithubApiUtil;
import org.jetbrains.plugins.github.api.GithubConnection;
import org.jetbrains.plugins.github.api.GithubUser;
import org.jetbrains.plugins.github.exceptions.GithubAuthenticationException;
import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException;
import org.jetbrains.plugins.github.util.*;
import javax.swing.*;
@@ -71,6 +71,7 @@ public class GithubSettingsPanel {
private JBLabel myAuthTypeLabel;
private JSpinner myTimeoutSpinner;
private JButton myCreateTokenButton;
private JBCheckBox myCloneUsingSshCheckBox;
private boolean myCredentialsModified;
@@ -145,7 +146,7 @@ public class GithubSettingsPanel {
);
}
catch (IOException ex) {
GithubNotifications.showErrorDialog(myPane, "Can't create API token", ex);
GithubNotifications.showErrorDialog(myPane, "Can't Create API Token", ex);
}
}
});
@@ -286,6 +287,7 @@ public class GithubSettingsPanel {
setPassword(mySettings.isAuthConfigured() ? DEFAULT_PASSWORD_TEXT : "");
setAuthType(mySettings.getAuthType());
setConnectionTimeout(mySettings.getConnectionTimeout());
myCloneUsingSshCheckBox.setSelected(mySettings.isCloneGitUsingSsh());
resetCredentialsModification();
}
@@ -294,12 +296,15 @@ public class GithubSettingsPanel {
mySettings.setAuthData(getAuthData(), true);
}
mySettings.setConnectionTimeout(getConnectionTimeout());
mySettings.setCloneGitUsingSsh(myCloneUsingSshCheckBox.isSelected());
resetCredentialsModification();
}
public boolean isModified() {
return myCredentialsModified || !Comparing.equal(mySettings.getHost(), getHost()) ||
!Comparing.equal(mySettings.getConnectionTimeout(), getConnectionTimeout());
return myCredentialsModified ||
!Comparing.equal(mySettings.getHost(), getHost()) ||
!Comparing.equal(mySettings.getConnectionTimeout(), getConnectionTimeout()) ||
!Comparing.equal(mySettings.isCloneGitUsingSsh(), myCloneUsingSshCheckBox.isSelected());
}
public void resetCredentialsModification() {
@@ -18,15 +18,18 @@ public class GithubShareDialog extends DialogWrapper {
private static final Pattern GITHUB_REPO_PATTERN = Pattern.compile("[a-zA-Z0-9_.-]+");
private final GithubSharePanel myGithubSharePanel;
private final Set<String> myAvailableNames;
private final Set<String> myAvailableRemotes;
public GithubShareDialog(final Project project, final Set<String> availableNames, final boolean privateRepoAllowed) {
public GithubShareDialog(Project project, Set<String> availableNames, Set<String> availableRemotes, boolean privateRepoAllowed) {
super(project);
myAvailableNames = availableNames;
myAvailableRemotes = availableRemotes;
myGithubSharePanel = new GithubSharePanel(this);
init();
setTitle("Share Project On GitHub");
setOKButtonText("Share");
myGithubSharePanel.setRepositoryName(project.getName());
myGithubSharePanel.setRemoteName(availableRemotes.isEmpty() ? "origin" : "github");
myGithubSharePanel.setPrivateRepoAvailable(privateRepoAllowed);
init();
updateOkButton();
@@ -53,7 +56,8 @@ public class GithubShareDialog extends DialogWrapper {
}
public void updateOkButton() {
final String repositoryName = getRepositoryName();
String repositoryName = getRepositoryName();
String remoteName = getRemoteName();
if (StringUtil.isEmpty(repositoryName)){
setErrorText("No repository name selected");
setOKActionEnabled(false);
@@ -64,6 +68,11 @@ public class GithubShareDialog extends DialogWrapper {
setOKActionEnabled(false);
return;
}
if (myAvailableRemotes.contains(remoteName)) {
setErrorText("Remote with selected name already exists");
setOKActionEnabled(false);
return;
}
if (!GITHUB_REPO_PATTERN.matcher(repositoryName).matches()){
setErrorText("Invalid repository name. Name should consist of letters, numbers, dashes, dots and underscores");
setOKActionEnabled(false);
@@ -85,6 +94,10 @@ public class GithubShareDialog extends DialogWrapper {
return myGithubSharePanel.getDescription();
}
public String getRemoteName() {
return myGithubSharePanel.getRemoteName();
}
@TestOnly
public void testSetRepositoryName(@NotNull String name) {
myGithubSharePanel.setRepositoryName(name);
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.plugins.github.ui.GithubSharePanel">
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="3" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="4" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="376" height="98"/>
<xy x="20" y="20" width="383" height="98"/>
</constraints>
<properties/>
<border type="none"/>
@@ -26,7 +26,7 @@
</component>
<scrollpane id="83208" class="com.intellij.ui.components.JBScrollPane">
<constraints>
<grid row="1" column="1" row-span="1" col-span="2" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false">
<grid row="2" column="1" row-span="1" col-span="2" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false">
<preferred-size width="250" height="100"/>
</grid>
</constraints>
@@ -41,7 +41,7 @@
</scrollpane>
<component id="d1ca7" class="javax.swing.JLabel">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Description"/>
@@ -57,9 +57,25 @@
</component>
<vspacer id="18a1f">
<constraints>
<grid row="2" column="2" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
<grid row="3" column="2" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<component id="539e4" class="javax.swing.JLabel">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Remote name:"/>
</properties>
</component>
<component id="7cb3e" class="javax.swing.JTextField" binding="myRemoteTextField">
<constraints>
<grid row="1" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
<preferred-size width="150" height="-1"/>
</grid>
</constraints>
<properties/>
</component>
</children>
</grid>
</form>
@@ -14,17 +14,21 @@ public class GithubSharePanel {
private JTextField myRepositoryTextField;
private JCheckBox myPrivateCheckBox;
private JTextArea myDescriptionTextArea;
private JTextField myRemoteTextField;
private final GithubShareDialog myGithubShareDialog;
public GithubSharePanel(final GithubShareDialog githubShareDialog) {
myGithubShareDialog = githubShareDialog;
myRepositoryTextField.getDocument().addDocumentListener(new DocumentAdapter() {
myPrivateCheckBox.setSelected(false);
DocumentAdapter changeListener = new DocumentAdapter() {
@Override
protected void textChanged(DocumentEvent e) {
myGithubShareDialog.updateOkButton();
}
});
myPrivateCheckBox.setSelected(false);
};
myRepositoryTextField.getDocument().addDocumentListener(changeListener);
myRemoteTextField.getDocument().addDocumentListener(changeListener);
}
public JPanel getPanel() {
@@ -43,6 +47,14 @@ public class GithubSharePanel {
myRepositoryTextField.setText(name);
}
public String getRemoteName() {
return myRemoteTextField.getText().trim();
}
public void setRemoteName(final String name) {
myRemoteTextField.setText(name);
}
public boolean isPrivate() {
return myPrivateCheckBox.isSelected();
}
@@ -62,6 +62,7 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S
public int CONNECTION_TIMEOUT = 5000;
public boolean VALID_GIT_AUTH = true;
public ThreeState CREATE_PULL_REQUEST_CREATE_REMOTE = ThreeState.UNSURE;
public boolean CLONE_GIT_USING_SSH = false;
}
public static GithubSettings getInstance() {
@@ -132,6 +133,10 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S
return passwordSafe.getSettings().getProviderType() == PasswordSafeSettings.ProviderType.MASTER_PASSWORD;
}
public boolean isCloneGitUsingSsh() {
return myState.CLONE_GIT_USING_SSH;
}
@NotNull
public ThreeState getCreatePullRequestCreateRemote() {
return myState.CREATE_PULL_REQUEST_CREATE_REMOTE;
@@ -161,6 +166,10 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S
myState.OPEN_IN_BROWSER_GIST = openInBrowserGist;
}
public void setCloneGitUsingSsh(boolean value) {
myState.CLONE_GIT_USING_SSH = value;
}
@NotNull
private String getPassword() {
String password;
@@ -209,6 +209,11 @@ public class GithubUrlUtil {
@NotNull
public static String getCloneUrl(@NotNull String user, @NotNull String repo) {
return getGithubHost() + "/" + user + "/" + repo + ".git";
if (GithubSettings.getInstance().isCloneGitUsingSsh()) {
return "git@" + getGitHostWithoutProtocol() + ":" + user + "/" + repo + ".git";
}
else {
return "https://" + getGitHostWithoutProtocol() + "/" + user + "/" + repo + ".git";
}
}
}
@@ -17,13 +17,13 @@ package org.jetbrains.plugins.gradle.execution.test.runner;
import com.intellij.execution.Location;
import com.intellij.execution.PsiLocation;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.testIntegration.TestLocationProvider;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -43,6 +43,7 @@ public class GradleUrlProvider implements TestLocationProvider {
@NotNull
public List<Location> getLocation(@NotNull String protocolId, @NotNull String locationData, Project project) {
if (!PROTOCOL_ID.equals(protocolId)) return Collections.emptyList();
if (DumbService.isDumb(project)) return Collections.emptyList();
final String className = extractFullClassName(locationData);
if (className == null) return Collections.emptyList();
@@ -527,15 +527,15 @@ public class JavaFxPsiUtil {
return false;
}
public static PsiType getWrappedPropertyType(PsiField field, final Project project, final Map<String, PsiType> typeMap) {
final PsiType fieldType = field.getType();
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(fieldType);
final PsiClass fieldClass = resolveResult.getElement();
if (fieldClass == null) return fieldType;
return CachedValuesManager.getManager(project).getCachedValue(field, new CachedValueProvider<PsiType>() {
public static PsiType getWrappedPropertyType(final PsiField field, final Project project, final Map<String, PsiType> typeMap) {
return CachedValuesManager.getCachedValue(field, new CachedValueProvider<PsiType>() {
@Nullable
@Override
public Result<PsiType> compute() {
final PsiType fieldType = field.getType();
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(fieldType);
final PsiClass fieldClass = resolveResult.getElement();
if (fieldClass == null) return Result.create(fieldType, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT);
PsiType substitute = null;
for (String typeName : typeMap.keySet()) {
if (InheritanceUtil.isInheritor(fieldType, typeName)) {
@@ -28,6 +28,7 @@ import org.junit.runner.manipulation.Filter;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.Parameterized;
import org.junit.runners.Suite;
import org.junit.runners.model.FrameworkMethod;
import java.io.BufferedReader;
@@ -324,13 +325,14 @@ public class JUnit4TestRunnerUtil {
}
}
private static class SelectedParameterizedRunner extends Parameterized {
private static class SelectedParameterizedRunner extends Suite {
public static final List NO_RUNNERS = new ArrayList();
private final String myName;
private final String myMethodName;
private Parameterized myRunnerClass;
public SelectedParameterizedRunner(Class clazz, String name, String methodName, Class runnerClass) throws Throwable {
super(clazz);
super(clazz, NO_RUNNERS);
myName = name;
myMethodName = methodName;
myRunnerClass = (Parameterized)runnerClass.getConstructor(new Class[] {Class.class}).newInstance(new Object[]{clazz});

Some files were not shown because too many files have changed in this diff Show More