@archznn/xavva 2.6.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -0
- package/package.json +1 -1
- package/src/commands/DeployCommand.ts +2 -1
- package/src/commands/EncodingCommand.ts +351 -0
- package/src/commands/HelpCommand.ts +15 -0
- package/src/config/versions.ts +63 -0
- package/src/di/container.ts +226 -0
- package/src/errors/ErrorHandler.ts +249 -0
- package/src/errors/XavvaError.ts +273 -0
- package/src/index.ts +98 -96
- package/src/services/AuditService.ts +3 -2
- package/src/services/BrowserService.ts +127 -16
- package/src/services/DeployWatcher.ts +183 -0
- package/src/services/EmbeddedTomcatService.ts +5 -19
- package/src/services/EncodingService.ts +548 -0
- package/src/services/FileWatcher.ts +243 -0
- package/src/services/TomcatService.ts +9 -5
- package/src/types/args.ts +136 -0
- package/src/types/config.ts +6 -0
- package/src/types/index.ts +7 -0
- package/src/utils/PathUtils.ts +221 -0
- package/src/utils/config.ts +6 -0
- package/src/utils/parsers/JavaParser.ts +413 -0
- package/src/utils/platform.ts +2 -2
- package/src/services/WatcherService.ts +0 -117
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Container de Injeção de Dependência (DI) simplificado
|
|
3
|
+
* Centraliza a criação e injeção de serviços
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { AppConfig } from "../types/config";
|
|
7
|
+
import { ProjectService } from "../services/ProjectService";
|
|
8
|
+
import { TomcatService } from "../services/TomcatService";
|
|
9
|
+
import { BuildService } from "../services/BuildService";
|
|
10
|
+
import { BuildCacheService } from "../services/BuildCacheService";
|
|
11
|
+
import { AuditService } from "../services/AuditService";
|
|
12
|
+
import { DashboardService } from "../services/DashboardService";
|
|
13
|
+
import { LogAnalyzer } from "../services/LogAnalyzer";
|
|
14
|
+
import { DeployCommand } from "../commands/DeployCommand";
|
|
15
|
+
import { BuildCommand } from "../commands/BuildCommand";
|
|
16
|
+
import { StartCommand } from "../commands/StartCommand";
|
|
17
|
+
import { LogsCommand } from "../commands/LogsCommand";
|
|
18
|
+
import { AuditCommand } from "../commands/AuditCommand";
|
|
19
|
+
import { ProfilesCommand } from "../commands/ProfilesCommand";
|
|
20
|
+
import { RunCommand } from "../commands/RunCommand";
|
|
21
|
+
import { HelpCommand } from "../commands/HelpCommand";
|
|
22
|
+
import { DoctorCommand } from "../commands/DoctorCommand";
|
|
23
|
+
import { DepsCommand } from "../commands/DepsCommand";
|
|
24
|
+
import { TomcatCommand } from "../commands/TomcatCommand";
|
|
25
|
+
import { EncodingCommand } from "../commands/EncodingCommand";
|
|
26
|
+
import { DocsCommand } from "../commands/DocsCommand";
|
|
27
|
+
import type { Command } from "../commands/Command";
|
|
28
|
+
import { Logger } from "../utils/ui";
|
|
29
|
+
|
|
30
|
+
export interface Services {
|
|
31
|
+
projectService: ProjectService;
|
|
32
|
+
tomcatService: TomcatService;
|
|
33
|
+
buildCacheService: BuildCacheService;
|
|
34
|
+
buildService: BuildService;
|
|
35
|
+
auditService: AuditService;
|
|
36
|
+
dashboardService: DashboardService;
|
|
37
|
+
logAnalyzer: LogAnalyzer;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface Commands {
|
|
41
|
+
deploy: DeployCommand;
|
|
42
|
+
dev: DeployCommand;
|
|
43
|
+
build: BuildCommand;
|
|
44
|
+
start: StartCommand;
|
|
45
|
+
logs: LogsCommand;
|
|
46
|
+
audit: AuditCommand;
|
|
47
|
+
profiles: ProfilesCommand;
|
|
48
|
+
run: RunCommand;
|
|
49
|
+
debug: RunCommand;
|
|
50
|
+
help: HelpCommand;
|
|
51
|
+
doctor: DoctorCommand;
|
|
52
|
+
deps: DepsCommand;
|
|
53
|
+
tomcat: TomcatCommand;
|
|
54
|
+
encoding: EncodingCommand;
|
|
55
|
+
docs: DocsCommand;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export class DIContainer {
|
|
59
|
+
private config: AppConfig;
|
|
60
|
+
private services: Partial<Services> = {};
|
|
61
|
+
private commands: Partial<Commands> = {};
|
|
62
|
+
private isInitialized = false;
|
|
63
|
+
|
|
64
|
+
constructor(config: AppConfig) {
|
|
65
|
+
this.config = config;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Inicializa todos os serviços e comandos
|
|
70
|
+
*/
|
|
71
|
+
initialize(): void {
|
|
72
|
+
if (this.isInitialized) {
|
|
73
|
+
Logger.debug("DI Container já inicializado");
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
this.initializeServices();
|
|
78
|
+
this.initializeCommands();
|
|
79
|
+
this.isInitialized = true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private initializeServices(): void {
|
|
83
|
+
// Serviços base (sem dependências ou com dependências simples)
|
|
84
|
+
const projectService = new ProjectService(this.config.project);
|
|
85
|
+
const buildCacheService = new BuildCacheService();
|
|
86
|
+
const dashboardService = new DashboardService(this.config);
|
|
87
|
+
const logAnalyzer = new LogAnalyzer(this.config.project);
|
|
88
|
+
|
|
89
|
+
// Configura Logger com dashboard
|
|
90
|
+
Logger.setDashboard(dashboardService);
|
|
91
|
+
|
|
92
|
+
// Serviços com dependências
|
|
93
|
+
const buildService = new BuildService(
|
|
94
|
+
this.config.project,
|
|
95
|
+
this.config.tomcat,
|
|
96
|
+
projectService,
|
|
97
|
+
buildCacheService
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const tomcatService = new TomcatService(this.config.tomcat);
|
|
101
|
+
tomcatService.setProjectService(projectService);
|
|
102
|
+
|
|
103
|
+
const auditService = new AuditService(this.config.tomcat);
|
|
104
|
+
|
|
105
|
+
this.services = {
|
|
106
|
+
projectService,
|
|
107
|
+
buildCacheService,
|
|
108
|
+
buildService,
|
|
109
|
+
tomcatService,
|
|
110
|
+
auditService,
|
|
111
|
+
dashboardService,
|
|
112
|
+
logAnalyzer,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private initializeCommands(): void {
|
|
117
|
+
const { tomcatService, buildService, auditService, dashboardService, logAnalyzer } = this.services;
|
|
118
|
+
|
|
119
|
+
if (!tomcatService || !buildService || !auditService || !dashboardService || !logAnalyzer) {
|
|
120
|
+
throw new Error("Serviços não inicializados corretamente");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Comandos que compartilham instâncias
|
|
124
|
+
const deployCmd = new DeployCommand(tomcatService, buildService);
|
|
125
|
+
const logsCmd = new LogsCommand(dashboardService, logAnalyzer);
|
|
126
|
+
|
|
127
|
+
this.commands = {
|
|
128
|
+
deploy: deployCmd,
|
|
129
|
+
dev: deployCmd, // dev reusa deploy
|
|
130
|
+
build: new BuildCommand(buildService),
|
|
131
|
+
start: new StartCommand(tomcatService),
|
|
132
|
+
logs: logsCmd,
|
|
133
|
+
audit: new AuditCommand(auditService),
|
|
134
|
+
profiles: new ProfilesCommand(this.services.projectService!),
|
|
135
|
+
run: new RunCommand(),
|
|
136
|
+
debug: new RunCommand(),
|
|
137
|
+
help: new HelpCommand(),
|
|
138
|
+
doctor: new DoctorCommand(),
|
|
139
|
+
deps: new DepsCommand(),
|
|
140
|
+
tomcat: new TomcatCommand(),
|
|
141
|
+
encoding: new EncodingCommand(),
|
|
142
|
+
docs: new DocsCommand(),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Obtém um serviço pelo nome
|
|
148
|
+
*/
|
|
149
|
+
getService<K extends keyof Services>(name: K): Services[K] {
|
|
150
|
+
if (!this.isInitialized) {
|
|
151
|
+
this.initialize();
|
|
152
|
+
}
|
|
153
|
+
const service = this.services[name];
|
|
154
|
+
if (!service) {
|
|
155
|
+
throw new Error(`Serviço '${name}' não encontrado no container`);
|
|
156
|
+
}
|
|
157
|
+
return service;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Obtém um comando pelo nome
|
|
162
|
+
*/
|
|
163
|
+
getCommand<K extends keyof Commands>(name: K): Commands[K] {
|
|
164
|
+
if (!this.isInitialized) {
|
|
165
|
+
this.initialize();
|
|
166
|
+
}
|
|
167
|
+
const command = this.commands[name];
|
|
168
|
+
if (!command) {
|
|
169
|
+
throw new Error(`Comando '${name}' não encontrado no container`);
|
|
170
|
+
}
|
|
171
|
+
return command;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Obtém todos os serviços
|
|
176
|
+
*/
|
|
177
|
+
getAllServices(): Services {
|
|
178
|
+
if (!this.isInitialized) {
|
|
179
|
+
this.initialize();
|
|
180
|
+
}
|
|
181
|
+
return this.services as Services;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Obtém todos os comandos
|
|
186
|
+
*/
|
|
187
|
+
getAllCommands(): Commands {
|
|
188
|
+
if (!this.isInitialized) {
|
|
189
|
+
this.initialize();
|
|
190
|
+
}
|
|
191
|
+
return this.commands as Commands;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Registra um serviço customizado (útil para testes)
|
|
196
|
+
*/
|
|
197
|
+
registerService<K extends keyof Services>(name: K, service: Services[K]): void {
|
|
198
|
+
this.services[name] = service;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Registra um comando customizado (útil para testes)
|
|
203
|
+
*/
|
|
204
|
+
registerCommand<K extends keyof Commands>(name: K, command: Commands[K]): void {
|
|
205
|
+
this.commands[name] = command;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Singleton para uso global
|
|
210
|
+
let globalContainer: DIContainer | null = null;
|
|
211
|
+
|
|
212
|
+
export function createContainer(config: AppConfig): DIContainer {
|
|
213
|
+
globalContainer = new DIContainer(config);
|
|
214
|
+
return globalContainer;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function getContainer(): DIContainer {
|
|
218
|
+
if (!globalContainer) {
|
|
219
|
+
throw new Error("Container não inicializado. Chame createContainer primeiro.");
|
|
220
|
+
}
|
|
221
|
+
return globalContainer;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function resetContainer(): void {
|
|
225
|
+
globalContainer = null;
|
|
226
|
+
}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ErrorHandler centralizado
|
|
3
|
+
* Trata todos os erros do aplicativo de forma uniforme
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
XavvaError,
|
|
8
|
+
isOperationalError,
|
|
9
|
+
getExitCode,
|
|
10
|
+
NetworkError,
|
|
11
|
+
FileSystemError,
|
|
12
|
+
BuildError,
|
|
13
|
+
TomcatError,
|
|
14
|
+
ConfigError
|
|
15
|
+
} from "./XavvaError";
|
|
16
|
+
import { Logger } from "../utils/ui";
|
|
17
|
+
import { ProcessManager } from "../utils/processManager";
|
|
18
|
+
|
|
19
|
+
export interface ErrorReport {
|
|
20
|
+
error: Error;
|
|
21
|
+
code: string;
|
|
22
|
+
exitCode: number;
|
|
23
|
+
isOperational: boolean;
|
|
24
|
+
context?: Record<string, unknown>;
|
|
25
|
+
timestamp: Date;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class ErrorHandler {
|
|
29
|
+
private static instance: ErrorHandler;
|
|
30
|
+
private errorHistory: ErrorReport[] = [];
|
|
31
|
+
private maxHistorySize = 10;
|
|
32
|
+
private isShuttingDown = false;
|
|
33
|
+
|
|
34
|
+
private constructor() {}
|
|
35
|
+
|
|
36
|
+
static getInstance(): ErrorHandler {
|
|
37
|
+
if (!ErrorHandler.instance) {
|
|
38
|
+
ErrorHandler.instance = new ErrorHandler();
|
|
39
|
+
}
|
|
40
|
+
return ErrorHandler.instance;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Trata qualquer erro de forma apropriada
|
|
45
|
+
*/
|
|
46
|
+
async handle(error: unknown, context?: Record<string, unknown>): Promise<void> {
|
|
47
|
+
if (this.isShuttingDown) return;
|
|
48
|
+
|
|
49
|
+
const normalizedError = this.normalizeError(error);
|
|
50
|
+
const report = this.createReport(normalizedError, context);
|
|
51
|
+
|
|
52
|
+
// Adiciona ao histórico
|
|
53
|
+
this.addToHistory(report);
|
|
54
|
+
|
|
55
|
+
// Log apropriado baseado no tipo de erro
|
|
56
|
+
if (normalizedError instanceof XavvaError) {
|
|
57
|
+
this.handleXavvaError(normalizedError);
|
|
58
|
+
} else {
|
|
59
|
+
this.handleUnexpectedError(normalizedError);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Se não for erro operacional, mostra stack trace em verbose
|
|
63
|
+
if (!report.isOperational) {
|
|
64
|
+
Logger.debug("Stack trace:");
|
|
65
|
+
Logger.debug(normalizedError.stack || "N/A");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Shutdown com código apropriado
|
|
69
|
+
const processManager = ProcessManager.getInstance();
|
|
70
|
+
await processManager.shutdown(report.exitCode);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Trata erro sem fazer shutdown (para operações que podem continuar)
|
|
75
|
+
*/
|
|
76
|
+
handleGraceful(error: unknown, context?: Record<string, unknown>): ErrorReport {
|
|
77
|
+
const normalizedError = this.normalizeError(error);
|
|
78
|
+
const report = this.createReport(normalizedError, context);
|
|
79
|
+
|
|
80
|
+
this.addToHistory(report);
|
|
81
|
+
|
|
82
|
+
if (normalizedError instanceof XavvaError) {
|
|
83
|
+
this.logXavvaError(normalizedError, false);
|
|
84
|
+
} else {
|
|
85
|
+
Logger.warn(`Erro inesperado: ${normalizedError.message}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return report;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Normaliza qualquer valor para Error
|
|
93
|
+
*/
|
|
94
|
+
private normalizeError(error: unknown): Error {
|
|
95
|
+
if (error instanceof Error) {
|
|
96
|
+
return error;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (typeof error === "string") {
|
|
100
|
+
return new Error(error);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (error && typeof error === "object" && "message" in error) {
|
|
104
|
+
return new Error(String((error as { message: unknown }).message));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return new Error("Erro desconhecido");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Cria um relatório de erro estruturado
|
|
112
|
+
*/
|
|
113
|
+
private createReport(error: Error, context?: Record<string, unknown>): ErrorReport {
|
|
114
|
+
return {
|
|
115
|
+
error,
|
|
116
|
+
code: error instanceof XavvaError ? error.code : "UNKNOWN_ERROR",
|
|
117
|
+
exitCode: getExitCode(error),
|
|
118
|
+
isOperational: isOperationalError(error),
|
|
119
|
+
context,
|
|
120
|
+
timestamp: new Date(),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Adiciona erro ao histórico (com limite)
|
|
126
|
+
*/
|
|
127
|
+
private addToHistory(report: ErrorReport): void {
|
|
128
|
+
this.errorHistory.push(report);
|
|
129
|
+
if (this.errorHistory.length > this.maxHistorySize) {
|
|
130
|
+
this.errorHistory.shift();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Trata erros específicos do Xavva
|
|
136
|
+
*/
|
|
137
|
+
private handleXavvaError(error: XavvaError): void {
|
|
138
|
+
this.logXavvaError(error, true);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Loga erro Xavva com formatação adequada
|
|
143
|
+
*/
|
|
144
|
+
private logXavvaError(error: XavvaError, isFatal: boolean): void {
|
|
145
|
+
const logMethod = isFatal ? Logger.error : Logger.warn;
|
|
146
|
+
|
|
147
|
+
// Cabeçalho do erro
|
|
148
|
+
logMethod.call(Logger, error.message);
|
|
149
|
+
|
|
150
|
+
// Detalhes adicionais se houver
|
|
151
|
+
if (error instanceof NetworkError) {
|
|
152
|
+
Logger.info("Dica", "Verifique sua conexão de internet e tente novamente");
|
|
153
|
+
} else if (error instanceof FileSystemError) {
|
|
154
|
+
Logger.info("Dica", "Verifique as permissões do arquivo/diretório");
|
|
155
|
+
} else if (error instanceof BuildError) {
|
|
156
|
+
Logger.info("Dica", "Use --verbose para ver detalhes completos do build");
|
|
157
|
+
} else if (error instanceof TomcatError) {
|
|
158
|
+
Logger.info("Dica", "Verifique se o Tomcat está configurado corretamente");
|
|
159
|
+
} else if (error instanceof ConfigError) {
|
|
160
|
+
Logger.info("Dica", "Verifique seu arquivo xavva.json");
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Código do erro em debug
|
|
164
|
+
Logger.debug(`Código do erro: ${error.code} (exit ${error.exitCode})`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Trata erros inesperados (bugs)
|
|
169
|
+
*/
|
|
170
|
+
private handleUnexpectedError(error: Error): void {
|
|
171
|
+
Logger.error("Erro inesperado:");
|
|
172
|
+
Logger.error(error.message);
|
|
173
|
+
Logger.newline();
|
|
174
|
+
Logger.info("Isso parece ser um bug", "Por favor, reporte em github.com/leorsousa05/Xavva/issues");
|
|
175
|
+
|
|
176
|
+
// Sempre mostra stack trace para erros inesperados
|
|
177
|
+
if (error.stack) {
|
|
178
|
+
Logger.newline();
|
|
179
|
+
Logger.dim("Stack trace:");
|
|
180
|
+
Logger.dim(error.stack.split("\n").slice(1, 5).join("\n"));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Obtém histórico de erros
|
|
186
|
+
*/
|
|
187
|
+
getErrorHistory(): ErrorReport[] {
|
|
188
|
+
return [...this.errorHistory];
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Limpa histórico de erros
|
|
193
|
+
*/
|
|
194
|
+
clearHistory(): void {
|
|
195
|
+
this.errorHistory = [];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Verifica se houve erros recentes de um tipo específico
|
|
200
|
+
*/
|
|
201
|
+
hasRecentError(code: string, withinMs: number = 60000): boolean {
|
|
202
|
+
const now = Date.now();
|
|
203
|
+
return this.errorHistory.some(
|
|
204
|
+
report =>
|
|
205
|
+
report.code === code &&
|
|
206
|
+
(now - report.timestamp.getTime()) < withinMs
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Wrapper para executar função com tratamento de erro automático
|
|
212
|
+
*/
|
|
213
|
+
async wrap<T>(
|
|
214
|
+
fn: () => Promise<T>,
|
|
215
|
+
context?: Record<string, unknown>
|
|
216
|
+
): Promise<T | undefined> {
|
|
217
|
+
try {
|
|
218
|
+
return await fn();
|
|
219
|
+
} catch (error) {
|
|
220
|
+
await this.handle(error, context);
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Wrapper para executar função sem shutdown em caso de erro
|
|
227
|
+
*/
|
|
228
|
+
wrapGraceful<T>(
|
|
229
|
+
fn: () => T,
|
|
230
|
+
fallback: T,
|
|
231
|
+
context?: Record<string, unknown>
|
|
232
|
+
): T {
|
|
233
|
+
try {
|
|
234
|
+
return fn();
|
|
235
|
+
} catch (error) {
|
|
236
|
+
this.handleGraceful(error, context);
|
|
237
|
+
return fallback;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Helper para uso rápido
|
|
243
|
+
export function handleError(error: unknown, context?: Record<string, unknown>): Promise<void> {
|
|
244
|
+
return ErrorHandler.getInstance().handle(error, context);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export function handleGraceful(error: unknown, context?: Record<string, unknown>): ErrorReport {
|
|
248
|
+
return ErrorHandler.getInstance().handleGraceful(error, context);
|
|
249
|
+
}
|